[](https://crates.io/crates/bevy_spritesheet_animation)
[](https://docs.rs/bevy_spritesheet_animation)
[](https://github.com/merwaaan/bevy_spritesheet_animation/actions)
[](LICENSE)
bevy_spritesheet_animation is a [Bevy](https://bevyengine.org/) plugin for animating sprites that are backed by spritesheets.

# Features
- Animate 2D and [3D sprites](#3d-sprites)! 🎉
- A single Bevy [component](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/components/spritesheet_animation/struct.SpritesheetAnimation.html) to add to your entities to play animations.
- Tunable parameters: [duration](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/animation/enum.AnimationDuration.html), [repetitions](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/animation/enum.AnimationRepeat.html), [direction](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/animation/enum.AnimationDirection.html), [easing](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/easing/enum.Easing.html).
- [Composable animations](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/animation/struct.Animation.html) from multiple clips.
- [Events](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/events/enum.AnimationEvent.html) to react to animations ending or reaching specific points.
- A [convenient API](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/spritesheet/struct.Spritesheet.html) to select frames in spritesheets.
> [!TIP]
> This crate is under active development. Please regularly check the [CHANGELOG](CHANGELOG.md) for recent changes.
# Quick start
1. Add the [SpritesheetAnimationPlugin](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/plugin/struct.SpritesheetAnimationPlugin.html) to your app
2. Use the [AnimationLibrary](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/library/struct.AnimationLibrary.html) resource to create new clips and animations
3. Add a [SpritesheetAnimation](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/components/spritesheet_animation/struct.SpritesheetAnimation.html) component to your entity
```rust
use bevy::prelude::*;
use bevy_spritesheet_animation::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// Add the plugin to enable animations.
// This makes the AnimationLibrary resource available to your systems.
.add_plugins(SpritesheetAnimationPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(
mut commands: Commands,
mut library: ResMut<AnimationLibrary>,
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
assets: Res<AssetServer>,
) {
// Create a clip
let spritesheet = Spritesheet::new(8, 8);
let clip = Clip::from_frames(spritesheet.row(3))
.with_duration(AnimationDuration::PerFrame(150));
let clip_id = library.register_clip(clip);
// Add this clip to an animation
let animation = Animation::from_clip(clip_id)
.with_repetitions(AnimationRepetition::Times(3));
let animation_id = library.register_animation(animation);
// 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 SpriteBundle
let texture = assets.load("character.png");
let layout = atlas_layouts.add(spritesheet.atlas_layout(96, 96));
commands.spawn((
SpriteBundle {
texture,
..default()
},
TextureAtlas {
layout,
..default()
},
// Add a SpritesheetAnimation component that references our newly created animation
SpritesheetAnimation::from_id(animation_id),
));
commands.spawn(Camera2dBundle::default());
}
```
# Overview
## Clips
A clip is a sequence of frames.
It is the most basic building block for creating animations.
Simple animations may contain a single clip while more complex animations may contain a sequence of clips.
Parameters like [duration](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/animation/enum.AnimationDuration.html), [repetitions](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/animation/enum.AnimationRepeat.html), [direction](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/animation/enum.AnimationDirection.html) and [easing](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/easing/enum.Easing.html) can be specified.
Use the [AnimationLibrary](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/library/struct.AnimationLibrary.html) resource to register new clips.
The clip can then be referenced in any number of animations.
```rust
fn setup(mut commands: Commands, mut library: ResMut<AnimationLibrary>) {
// Create a clip that uses some frames from a spritesheet
let spritesheet = Spritesheet::new(8, 8);
let clip = Clip::from_frames(spritesheet.column(2))
.with_duration(AnimationDuration::PerRepetition(1500))
.with_repetitions(5);
let clip_id = library.register_clip(clip);
// Add this clip to an animation
let animation = Animation::from_clip(clip_id);
// ...
}
```
## 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 tuning their parameters.
Use the [AnimationLibrary](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/library/struct.AnimationLibrary.html) resource to register new animation.
The animation can then be referenced in any number of SpritesheetAnimation component.
```rust
fn setup(mut commands: Commands, mut library: ResMut<AnimationLibrary>) {
// ... omitted: create and register a few clips
let animation = Animation::from_clips([
running_clip_id,
shooting_clip_id,
running_clip_id
])
.with_duration(AnimationDuration::PerRepetition(3000))
.with_direction(Animation::Direction::Backwards);
let animation_id = library.register_animation(animation);
// Assign the animation to an entity with the SpritesheetAnimation component
// ... omitted: load the sprite's texture and create an atlas
commands.spawn((
SpriteBundle {
texture,
..default()
},
TextureAtlas {
layout,
..default()
},
SpritesheetAnimation::from_id(animation_id),
));
}
```
## Think of clips and animations as assets!
Clips and animations should be created once.
You can then assign them to many entities.
### ❌ BAD
Do not create the same clip/animation for each entity that plays it.
```rust
fn spawn_enemies(mut commands: Commands, mut library: ResMut<AnimationLibrary>) {
// Creating identical animations gives more work to the plugin and degrades performance!
for _ in 0..100 {
let clip = Clip::from_frames([1, 2, 3]);
let clip_id = library.register_clip(clip);
let animation = Animation::from_clip(clip_id);
let animation_id = library.register_animation();
commands.spawn((
SpriteBundle { /* .... */ },
SpritesheetAnimation::from_id(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.
```rust
fn create_animation(mut library: ResMut<AnimationLibrary>) {
let clip = Clip::from_frames([1, 2, 3]);
let clip_id = library.register_clip(clip);
let animation = Animation::from_clip(clip_id);
let animation_id = library.register_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: AnimationId,
// enemy_firing: AnimationId,
// ... and so on ...
// }
library.name_animation(animation_id, "enemy running");
}
fn spawn_enemies(mut commands: Commands, library: Res<AnimationLibrary>) {
// 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((
SpriteBundle { /* .... */ },
SpritesheetAnimation::from_id(animation_id),
));
}
}
}
```
## 3D sprites

This crate also makes it easy to integrate 3D sprites into your games, which is not supported by Bevy out of the box.
[Sprite3dBundle](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/components/sprite3d/struct.Sprite3dBundle.html) contains all the necesary components to enable 3D sprites. Use [Sprite3dBuilder](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/components/sprite3d/struct.Sprite3dBuilder.html) to easily create one of those.
Animating a 3D sprite is the same as animating 2D sprites: simply attach a [SpritesheetAnimation](https://docs.rs/bevy_spritesheet_animation/latest/bevy_spritesheet_animation/components/spritesheet_animation/struct.SpritesheetAnimation.html) component to your entity.
```rust
fn spawn_character(mut commands: Commands, mut library: ResMut<AnimationLibrary>) {
// ...
let animation_id = library.register_animation(animation);
commands.spawn((
Sprite3dBuilder::from_image(texture.clone())
.with_atlas(atlas_layout)
.with_anchor(Anchor::BottomRight)
.build(),
SpritesheetAnimation::from_id(animation_id)
));
}
```
# More examples
For more examples, browse the [examples/](examples) directory.
| Example | Description |
| -------------------------------------- | ------------------------------------------------------------------------ |
| [basic](examples/basic.rs) | Shows how to create an animated sprite |
| [3d](examples/3d.rs) | Shows how to create 3D sprites |
| [progress](examples/progress.rs) | Shows how to control an animation |
| [composition](examples/composition.rs) | Shows how to create an animation with multiple clips |
| [parameters](examples/parameters.rs) | Shows the effect of each animation parameter |
| [character](examples/character.rs) | Shows how to create a controllable character with multiple animations |
| [events](examples/events.rs) | Shows how to react to animations reaching points of interest with events |
| [stress](examples/stress.rs) | Stress test with thousands of animated sprites (either 2D or 3D) |
# Compatibility
| bevy | bevy_spritesheet_animation |
| ---- | -------------------------- |
| 0.14 | 0.2.0 |
| 0.13 | 0.1.0 |
# Credits
- The character spritesheet used for the examples is CC0 from [thekingphoenix](https://opengameart.org/content/pixel-character-with-gun)