3 releases
0.1.0 | Apr 10, 2024 |
---|---|
0.1.0-beta.1 | Apr 8, 2024 |
0.1.0-beta.0 | Apr 7, 2024 |
#83 in Game dev
350 downloads per month
140KB
1.5K
SLoC
bevy_spritesheet_animation is a Bevy plugin for animating sprites that are backed by spritesheets.
Features
- A single Bevy component to add to your entities to play animations.
- Tunable parameters: duration, repetitions, direction, easing.
- Composable animations from multiple clips.
- Events to react to animations ending or reaching specific points.
- A convenient API to select frames in spritesheets.
Quick start
- Add the SpritesheetAnimationPlugin to your app
- Use the SpritesheetLibrary resource to create new clips and animations
- Add a SpritesheetAnimation component to your entity
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// Add the plugin to enable animations.
// This makes the SpritesheetLibrary resource available to your systems.
.add_plugins(SpritesheetAnimationPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(
mut commands: Commands,
mut library: ResMut<SpritesheetLibrary>,
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
assets: Res<AssetServer>,
) {
// Create an animation
let clip_id = library.new_clip(|clip| {
// You can configure this clip here (duration, number of repetitions, etc...)
// This clip will use all the frames in row 3 of the spritesheet
clip.push_frame_indices(Spritesheet::new(8, 8).row(3));
});
let animation_id = library.new_animation(|animation| {
// You can configure this animation here (duration, number of repetitions, etc...)
animation.add_stage(clip_id.into());
// This is a simple animation with a single clip but we can create more sophisticated
// animations with multiple clips, each one having different parameters.
//
// See the `composition` example for more details.
});
// Spawn a sprite using Bevy's built-in SpriteSheetBundle
let texture = assets.load("character.png");
let layout = atlas_layouts.add(TextureAtlasLayout::from_grid(
Vec2::new(96.0, 96.0),
8,
8,
None,
None,
));
commands.spawn((
SpriteSheetBundle {
texture,
atlas: TextureAtlas {
layout,
..default()
},
..default()
},
// Add a SpritesheetAnimation component that references our newly created animation
SpritesheetAnimation::from(animation_id),
));
commands.spawn(Camera2dBundle::default());
}
Overview
Animation clips
An animation clip is a reusable sequence of frames.
It is the most basic building block for creating animations.
Use the SpritesheetLibrary resource to create and configure a new clip.
The clip can then be referenced in any number of animations.
fn setup(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {
// Create a clip that uses some frames from a spritesheet
let clip_id = library.new_clip(|clip| {
clip
.push_frame_indices(Spritesheet::new(8, 8).column(2))
.set_default_duration(AnimationDuration::PerCycle(1500))
.set_default_repeat(5);
});
// Add this clip to an animation
let animation_id = library.new_animation(|animation| {
animation.add_stage(clip_id.into());
});
// ... Assign the animation to an entity with the SpritesheetAnimation component ...
}
Animations
In its simplest form, an animation is composed of a single clip that loops endlessly.
However, you're free to compose more sophisticated animations by chaining multiple clips and by tuning the animation parameters.
Use the SpritesheetLibrary resource to create a new animation.
The animation can then be referenced in any number of SpritesheetAnimation component.
fn setup(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {
// ...
let animation_id = library.new_animation(|animation| {
let mut stage1 = AnimationStage::from_clip(some_clip_id);
stage1
.set_repeat(5)
.set_easing(Easing::InOut(EasingVariety::Quadratic));
let mut stage2 = AnimationStage::from_clip(another_clip_id);
stage2
.set_duration(AnimationDuration::PerFrame(120))
.set_direction(Animation::Direction::Backwards);
animation
.add_stage(stage1)
.add_stage(stage2)
.set_duration(AnimationDuration::PerCycle(1000))
.set_direction(Animation::Direction::PingPong);
});
// ... Assign the animation to an entity with the SpritesheetAnimation component ...
}
Think of clips and animations as assets!
Clips and animations should be created once. You can then assign them to many entities.
❌ BAD
You should not create the same clip/animation for each entity that plays it.
fn spawn_enemies(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {
// Creating identical animations gives more work to the plugin and degrades performance!
for _ in 0..100 {
let clip_id = library.new_clip(|clip| { /* ... */ });
let animation_id = library.new_animation(|animation| { /* ... */ });
commands.spawn((
SpriteSheetBundle { /* .... */ },
SpritesheetAnimation::from(animation_id),
));
}
}
👍 GOOD
Instead, create clips/animations once and then reference them when needed.
For instance, you can create all your animations in a setup system, give them unique names and then assign them to entities at a later stage.
fn create_animation(mut library: ResMut<SpritesheetLibrary>) {
let clip_id = library.new_clip(|clip| { /* ... */ });
let animation_id = library.new_animation(|animation| { /* ... */ });
// Here, we name the animation to make it easy to retrieve it in other systems.
//
// Alternatively, you may prefer to store the animation ID yourself.
// For instance, in a Bevy Resource that contains the IDs of all your clips/animations.
// Something like:
//
// #[derive(Resource)]
// struct GameAnimations {
// enemy_running: Option<AnimationId>,
// enemy_firing: Option<AnimationId>,
// ... and so on ...
// }
library.name_animation(animation_id, "enemy running");
}
fn spawn_enemies(mut commands: Commands, library: Res<SpritesheetLibrary>) {
// Retrieve our animation and assign it to many entities
if let Some(animation_id) = libray.animation_with_name("enemy running") {
for _ in 0..100 {
commands.spawn((
SpriteSheetBundle { /* .... */ },
SpritesheetAnimation::from(animation_id),
));
}
}
}
More examples
For more examples, browse the examples/ directory.
Example | Description |
---|---|
basic | Minimal example showing how to create an animated sprite |
composition | Advanced example showing how to create an animation with multiple stages |
parameters | Shows the effect of each parameter |
character | Shows how to create a controllable character with multiple animations |
events | Shows how to react to animations reaching points of interest with events |
stress | A stress test with thousands of animated sprites |
Compatibility
bevy | bevy_spritesheet_animation |
---|---|
0.13 | 0.1.0 |
Credits
- The character spritesheet used for the examples is CC0 from thekingphoenix
Dependencies
~39–80MB
~1M SLoC