Crates.io | bevy_animations |
lib.rs | bevy_animations |
version | 0.5.62 |
source | src |
created_at | 2023-03-11 07:55:57.918733 |
updated_at | 2024-05-04 20:50:01.855007 |
description | 2d Game Animation Engine built for Bevy |
homepage | https://github.com/Double-Dot-Interactive/bevy_animations |
repository | https://github.com/Double-Dot-Interactive/bevy_animations.git |
max_upload_size | |
id | 807080 |
size | 121,813 |
Bevy Animations is still in beta and may incurr major API and backend changes in the future.
use bevy_animations::AnimationsPlugin;
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(AnimationsPlugin {
pixels_per_meter: 20. // your desired pixels_per_meter
})
.run()
}
meters_per_frame
for each frameCommands
like thisuse bevy_animations::*;
use bevy::prelude::*;
fn entity_setup(
mut commands: Commands,
animations: ResMut<Animations>
) {
let entity = commands.spawn(
Animator::default(), // the `AnimationDirection` component is needed on the entity to determine the direction
SpriteSheetBundle {
texture_atlas: // your sprite sheet handle
transform: Transform::from_xyz(0., 0., 0.) // your desired location in the `World`
}
/* The rest of your entity configuration */
);
}
Note if you don't add the AnimationDirection
component to your entity it will seem as though your animations will never be inserted because bevy_animations
is looking for the
AnimationDirection
component in it's Query
s
ResMut<Animations>
like thisanimations.insert_animation(
NewAnimation {
handle: player_movement_texture.clone(), /* the handle for the TextureAtlas */
animation: AnimationType::Timed(
TransformAnimation::new(
Vec::from(PLAYER_RUNNING_FRAMES), /* animation_frames */
PLAYER_RUNNING_METERS_PER_FRAME, /* meters_per_frame */
Vec2::new(14., 38.), /* frame */
AnimationDirectionIndexes::FlipBased(FlipBasedDirection { /* direction_indexes */
left_direction_is_flipped: true,
x_direction_index: 3,
}),
true, /* repeating */
),
"player_running", /* AnimationName */
),
},
Some(player_entity), /* specify an entity to add the animation to now instead of later */
)
Note if you have a one directional animation you can use AnimationDirectionIndexes::one_directional()
Note it is on you to make sure you are passing the correct strings to bevy_animations to animate your entity
TimedAnimation
like thisanimations.insert_animation(
NewAnimation {
handle: player_movement_texture.clone(), /* the handle for the TextureAtlas */
animation: AnimationType::Timed(
TimedAnimation::new(
Vec::from(PLAYER_RUNNING_FRAMES), /* animation_frames */
Vec::from(PLAYER_RUNNING_TIMINGS), /* frame_timings_in_secs */
Vec2::new(14., 38.), /* frame */
AnimationDirectionIndexes::FlipBased(FlipBasedDirection { /* direction_indexes */
left_direction_is_flipped: true,
x_direction_index: 3,
}),
true, /* repeating */
false, /* blocking */
0 /* blocking_priory */
),
"player_running", /* AnimationName */
),
},
Some(player_entity), /* specify an entity to add the animation to now instead of later */
)
EventWriter<AnimationEvent>
like thisfn move_player(
mut event_writer: EventWriter<AnimationEvent>,
player_query: Query<Entity, With<Player>>
) {
// your move logic here...
event_writer.send(AnimationEvent("player_running", entity));
}
Note that you can send an event of the same name multiple times even while an animation is in progress without ruining it
Note an animation that has been sent will animate till end or repeat forever
AnimatingEntity
like thisfn move_player(
mut event_writer: EventWriter<AnimationEvent>,
mut query: Query<&mut Animator, With<Player>> // specify the `With` to get the entity associated with your custom component
) {
// your move logic here...
let mut animator = query.single_mut(); // get the direction via query
animator.change_direction(AnimationDirection::Left); // the direction can be changed like this
event_writer.send(AnimationEvent("player_running", entity));
}
player_running
animation to player_die
in another system where you could check collisions like thisfn check_collisions(
mut commands: Commands,
rapier_context: Res<RapierContext> // great 2d physics engine for lots of things we are using it for collision detection
mut event_writer: EventWriter<AnimationEvent>,
player_query: Query<Entity, With<Player>>,
bullet_query: Query<Entity, With<Bullet>>
) {
let player_entity = player_query.single();
for bullet_entity in bullet_query.iter() {
if let Some(_) = context.contact_pair(bullet_entity, player_entity) {
// send the event for the animating entity
event_writer.send(AnimationEvent("player_die", entity));
// despawn the entity after death
commands.entity(player_entity).despawn();
commands.entity(bullet_entity).despawn();
}
}
}
Note that bevy_animations
will automatically remove your entity from it's own data structure if it doesn't exist in the World
i.e when the entity despawns via .despawn()
Note there is no functionality internally yet for doing a task like despawning an entity only after an animation is finished. This can be accomplished on your own however.
bevy | bevy_animations |
---|---|
0.12.x | 0.5.x |
0.11.x | 0.4.x |
0.10.x | 0.3.x |
0.9.x | 0.2.x |
If you need more in depth Documentation and more examples for all of the current implementations read the bevy_animations book or visit the api docs
bevy_animations is open-source forever. You can contribute via the GitHub Repo