Skip to content

Commit 88577fb

Browse files
committed
WIP
1 parent 7005383 commit 88577fb

46 files changed

Lines changed: 3936 additions & 3826 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
# Changelog
22

3+
## 5.0.0 - 2025-??-??
4+
5+
This release comes with a significant rework of the high-level API that tightens up the relationships between spritesheets, clips and animations.
6+
7+
It also removes the `AnimationLibrary` resource in favor of registering animations in `Assets<Animation>` like other Bevy assets.
8+
9+
As a consequence of the `AnimationLibrary` removal, it's no longer possible to name clips, animations or markers to retrieve them by name across systems.
10+
An alternative (and safer!) way to retrieve animation data is to save it in custom resources, as demonstrated in the examples (eg. `examples/character.rs`).
11+
If you still prefer to use names, you may want to define such a custom resource as -- for instance -- a `HashMap<String, Handle<Animation>>`.
12+
13+
Migrating to this new version should be pretty straightforward. Please check out the updated examples and documentation!
14+
15+
### Added
16+
17+
- `Spritesheet` can now create animation-ready sprites, 3D sprites, UI images, cursors and texture atlases to reduce boilerplate when creating animated entities
18+
- Add an example showcasing animated UI images
19+
20+
### Changed
21+
22+
- Animations are now exclusively created with `Spritesheet::create_animation()` which returns an `AnimationBuilder`
23+
- Clips are now exclusively created with `AnimationBuilder::start_clip()`/`AnimationBuilder::copy_clip()`
24+
- Rename `AnimationMarkerId` to `Marker`
25+
26+
### Removed
27+
28+
- Remove the `AnimationLibrary` resource (you can now register animations in `Assets<Animation>`)
29+
30+
### Fixed
31+
32+
- Fix a few panics when selecting out-of-bounds cells in spritesheets
33+
334
## 4.0.1 - 2025-10-09
435

536
No actual changes. Had to bump the version to republish the crate and fix docs.rs failing to build the documentation.
@@ -9,7 +40,7 @@ No actual changes. Had to bump the version to republish the crate and fix docs.r
940
### Added
1041

1142
- Add support for Bevy 0.17
12-
- Add an example showing how to setup an animated cursor
43+
- Add an example showcasing animated cursors
1344

1445
### Changed
1546

@@ -157,7 +188,7 @@ To create a variant of a clip, just clone and reconfigure it before registering
157188

158189
### Fixed
159190

160-
- Switch `new_clip`/`new_animatio`n closures to FnMut to allow mutations
191+
- Switch `new_clip`/`new_animation` closures to FnMut to allow mutations
161192

162193
## 0.1.0 - 2024-04-10
163194

README.md

Lines changed: 190 additions & 176 deletions
Large diffs are not rendered by default.

TODO.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Make events optional
2+
3+
Events are always emitted, even when users never use them.
4+
This becomes costly when many sprites are spawned.
5+
Put them behind a feature flag or add a runtime option to toggle them.
6+
7+
# Add the current animation repetition to events
8+
9+
We have it available so might as well use it.
10+
11+
# Optimize playback
12+
13+
There's currently a lot of allocations during playback (esp. for events).
14+
Use a single storage for all sprites instead of allocating one at each sprite update.

assets/cursor.png

6.77 KB
Loading

assets/hearts.png

713 Bytes
Loading

examples/3d.rs

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,22 @@
11
// This example shows how to create 3D sprites.
22

3-
#[path = "./common/mod.rs"]
4-
pub mod common;
5-
63
use bevy::{prelude::*, sprite::Anchor};
74
use bevy_spritesheet_animation::prelude::*;
85
use rand::{Rng, seq::IndexedRandom as _};
96

107
fn main() {
118
App::new()
12-
.add_plugins((
13-
DefaultPlugins.set(ImagePlugin::default_nearest()),
14-
SpritesheetAnimationPlugin,
15-
))
9+
.add_plugins((DefaultPlugins, SpritesheetAnimationPlugin))
1610
.add_systems(Startup, spawn_sprites)
1711
.add_systems(Update, (update_on_keypress, orbit, draw_gizmos))
1812
.run();
1913
}
2014

2115
fn spawn_sprites(
2216
mut commands: Commands,
23-
mut library: ResMut<AnimationLibrary>,
24-
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
2517
assets: Res<AssetServer>,
18+
mut animations: ResMut<Assets<Animation>>,
19+
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
2620
) {
2721
// 3D sprites require a 3D camera
2822

@@ -33,24 +27,19 @@ fn spawn_sprites(
3327

3428
// Create an animation as usual
3529

36-
let spritesheet = Spritesheet::new(8, 8);
37-
38-
let clip = Clip::from_frames(spritesheet.row(3));
39-
40-
let clip_id = library.register_clip(clip);
30+
let image = assets.load("character.png");
4131

42-
let animation = Animation::from_clip(clip_id);
32+
let spritesheet = Spritesheet::new(&image, 8, 8);
4333

44-
let animation_id = library.register_animation(animation);
34+
let animation = spritesheet.create_animation().add_row(3).build();
4535

46-
// Create an image and a texture atlas like you would for any Bevy sprite
36+
let animation_handle = animations.add(animation);
4737

48-
let image = assets.load("character.png");
38+
// Create an image and a texture atlas like you would for 2D sprites
4939

50-
let atlas = TextureAtlas {
51-
layout: atlas_layouts.add(spritesheet.atlas_layout(96, 96)),
52-
..default()
53-
};
40+
let atlas = spritesheet
41+
.with_size_hint(768, 768)
42+
.atlas(&mut atlas_layouts);
5443

5544
// Spawn 3D sprites
5645

@@ -79,7 +68,7 @@ fn spawn_sprites(
7968
for (i, sprite) in sprites.into_iter().enumerate() {
8069
commands.spawn((
8170
sprite,
82-
SpritesheetAnimation::from_id(animation_id),
71+
SpritesheetAnimation::new(animation_handle.clone()),
8372
Orbit {
8473
start_angle: i as f32 * std::f32::consts::TAU / sprite_count as f32,
8574
},
@@ -95,9 +84,8 @@ fn spawn_sprites(
9584

9685
// Help text
9786

98-
commands.spawn((Text(
99-
"C: random colors\nX: flip on X\nY: flip on Y\nA: random anchors\nS: random sizes\nR: reset".to_owned()),
100-
TextFont::from_font_size(30.0)
87+
commands.spawn(Text::new(
88+
"C: random colors\nX: flip on X\nY: flip on Y\nA: random anchors\nS: random sizes\nR: reset"
10189
));
10290
}
10391

@@ -166,9 +154,11 @@ struct Orbit {
166154
}
167155

168156
fn orbit(time: Res<Time>, mut query: Query<(&Orbit, &mut Transform)>) {
157+
let secs_elapsed = time.elapsed_secs();
158+
169159
for (orbit, mut transform) in &mut query {
170-
transform.translation.x = (orbit.start_angle + time.elapsed_secs()).cos() * 1500.0;
171-
transform.translation.z = (orbit.start_angle + time.elapsed_secs()).sin() * 1500.0;
160+
transform.translation.x = (orbit.start_angle + secs_elapsed).cos() * 1500.0;
161+
transform.translation.z = (orbit.start_angle + secs_elapsed).sin() * 1500.0;
172162
}
173163
}
174164

examples/basic.rs

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,63 @@
11
// This example shows how to create a simple animated sprite.
22

3-
#[path = "./common/mod.rs"]
4-
pub mod common;
5-
63
use bevy::prelude::*;
74
use bevy_spritesheet_animation::prelude::*;
85

96
fn main() {
107
App::new()
11-
.add_plugins(DefaultPlugins)
12-
// Add the plugin to enable animations.
13-
// This makes the AnimationLibrary resource available to your systems.
8+
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
9+
// Add the plugin to enable animations
10+
//
11+
// This configures the app to play animations for entities with a SpritesheetAnimation component.
12+
// This also makes the Assets<Animation> resource available to your systems.
1413
.add_plugins(SpritesheetAnimationPlugin)
15-
.add_systems(
16-
Startup,
17-
(create_animation, spawn_sprite.after(create_animation)),
18-
)
14+
.add_systems(Startup, create_animated_sprite)
1915
.run();
2016
}
2117

22-
fn create_animation(mut commands: Commands, mut library: ResMut<AnimationLibrary>) {
18+
fn create_animated_sprite(
19+
mut commands: Commands,
20+
assets: Res<AssetServer>,
21+
mut animations: ResMut<Assets<Animation>>,
22+
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
23+
) {
2324
commands.spawn(Camera2d);
2425

25-
// Create a clip that references some frames from a spritesheet
26-
27-
let spritesheet = Spritesheet::new(8, 8);
28-
29-
let clip = Clip::from_frames(spritesheet.row(3));
30-
31-
let clip_id = library.register_clip(clip);
26+
// Create an animation from a row of an 8x8 spritesheet
27+
//
28+
// This is a simple animation made of a single clip but we can create more sophisticated animations with multiple clips, each one having different parameters.
29+
//
30+
// See the `composition` example for more details.
3231

33-
// Create an animation that uses the clip
32+
let image = assets.load("character.png");
3433

35-
let animation = Animation::from_clip(clip_id);
34+
let spritesheet = Spritesheet::new(&image, 8, 8);
3635

37-
let animation_id = library.register_animation(animation);
36+
let animation = spritesheet
37+
.create_animation()
38+
.add_row(3)
39+
.set_duration(AnimationDuration::PerFrame(100))
40+
.build();
3841

39-
// Name the animation to retrieve it from other systems
42+
// Register the animation as an asset
4043

41-
library.name_animation(animation_id, "walk").unwrap();
44+
let animation_handle = animations.add(animation);
4245

43-
// This is a simple animation with a single clip but we can create more sophisticated
44-
// animations with multiple clips, each one having different parameters.
46+
// Create a regular Bevy sprite
4547
//
46-
// See the `composition` example for more details.
47-
}
48-
49-
// We split the setup in two separate systems to show how to retrieve animations from their name
50-
51-
fn spawn_sprite(
52-
mut commands: Commands,
53-
library: Res<AnimationLibrary>,
54-
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
55-
assets: Res<AssetServer>,
56-
) {
57-
// Retrieve our animation from the library
58-
59-
if let Some(animation_id) = library.animation_with_name("walk") {
60-
// Create an image and a texture atlas like you would for any Bevy sprite
61-
62-
let image = assets.load("character.png");
48+
// Here we use the spritesheet to automatically generate the animation-ready Bevy sprite.
49+
// This is optional and you may prefer to build the sprite manually.
6350

64-
let atlas = TextureAtlas {
65-
layout: atlas_layouts.add(Spritesheet::new(8, 8).atlas_layout(96, 96)),
66-
..default()
67-
};
51+
let sprite = spritesheet
52+
.with_size_hint(768, 768)
53+
.sprite(&mut atlas_layouts);
6854

69-
// Spawn a sprite with a SpritesheetAnimation component that references our animation
55+
// Spawn the sprite with a SpritesheetAnimation component that references our animation
7056

71-
commands.spawn((
72-
Sprite::from_atlas_image(image, atlas),
73-
SpritesheetAnimation::from_id(animation_id),
74-
));
75-
}
57+
commands.spawn((
58+
// This is a regular Bevy sprite
59+
sprite,
60+
// This is the component that animates the sprite
61+
SpritesheetAnimation::new(animation_handle),
62+
));
7663
}

0 commit comments

Comments
 (0)