diff --git a/Cargo.toml b/Cargo.toml index a04c8bcca5..6e530c6cb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -465,6 +465,17 @@ description = "Renders a sprite" category = "2D Rendering" wasm = true +[[example]] +name = "sprite_animation" +path = "examples/2d/sprite_animation.rs" +doc-scrape-examples = true + +[package.metadata.example.sprite_animation] +name = "Sprite Animation" +description = "Animates a sprite in response to an event" +category = "2D Rendering" +wasm = true + [[example]] name = "sprite_flipping" path = "examples/2d/sprite_flipping.rs" diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index 0ad06f6afc..a9a1736fa0 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -42,6 +42,7 @@ pub struct SpriteBundle { /// /// Check the following examples for usage: /// - [`animated sprite sheet example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs) +/// - [`sprite animation event example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_animation.rs) /// - [`texture atlas example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs) #[deprecated( since = "0.14.0", diff --git a/crates/bevy_sprite/src/texture_atlas.rs b/crates/bevy_sprite/src/texture_atlas.rs index 2292354289..9af933a43a 100644 --- a/crates/bevy_sprite/src/texture_atlas.rs +++ b/crates/bevy_sprite/src/texture_atlas.rs @@ -12,6 +12,7 @@ use bevy_utils::HashMap; /// [`TextureAtlasBuilder`]). /// /// [Example usage animating sprite.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs) +/// [Example usage animating sprite in response to an event.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_animation.rs) /// [Example usage loading sprite sheet.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs) /// /// [`TextureAtlasBuilder`]: crate::TextureAtlasBuilder @@ -40,6 +41,7 @@ pub struct TextureAtlasLayout { /// /// Check the following examples for usage: /// - [`animated sprite sheet example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs) +/// - [`sprite animation event example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_animation.rs) /// - [`texture atlas example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs) #[derive(Component, Default, Debug, Clone, Reflect)] pub struct TextureAtlas { diff --git a/examples/2d/sprite_animation.rs b/examples/2d/sprite_animation.rs new file mode 100644 index 0000000000..8f6a343e99 --- /dev/null +++ b/examples/2d/sprite_animation.rs @@ -0,0 +1,158 @@ +//! Animates a sprite in response to a keyboard event. +//! +//! See `sprite_sheet.rs` for an example where the sprite animation loops indefinitely. + +use std::time::Duration; + +use bevy::input::common_conditions::input_just_pressed; +use bevy::prelude::*; + +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) // prevents blurry sprites + .add_systems(Startup, setup) + .add_systems(Update, execute_animations) + .add_systems( + Update, + ( + // press the right arrow key to animate the right sprite + trigger_animation::.run_if(input_just_pressed(KeyCode::ArrowRight)), + // press the left arrow key to animate the left sprite + trigger_animation::.run_if(input_just_pressed(KeyCode::ArrowLeft)), + ), + ) + .run(); +} + +// This system runs when the user clicks the left arrow key or right arrow key +fn trigger_animation(mut query: Query<&mut AnimationConfig, With>) { + // we expect the Component of type S to be used as a marker Component by only a single entity + let mut animation = query.single_mut(); + // we create a new timer when the animation is triggered + animation.frame_timer = AnimationConfig::timer_from_fps(animation.fps); +} + +#[derive(Component)] +struct AnimationConfig { + first_sprite_index: usize, + last_sprite_index: usize, + fps: u8, + frame_timer: Timer, +} + +impl AnimationConfig { + fn new(first: usize, last: usize, fps: u8) -> Self { + Self { + first_sprite_index: first, + last_sprite_index: last, + fps, + frame_timer: Self::timer_from_fps(fps), + } + } + + fn timer_from_fps(fps: u8) -> Timer { + Timer::new(Duration::from_secs_f32(1.0 / (fps as f32)), TimerMode::Once) + } +} + +// This system loops through all the sprites in the `TextureAtlas`, from `first_sprite_index` to +// `last_sprite_index` (both defined in `AnimationConfig`). +fn execute_animations( + time: Res