1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
#![warn( future_incompatible, nonstandard_style, rust_2018_idioms, missing_docs, clippy::pedantic )] #![allow(clippy::needless_pass_by_value, clippy::module_name_repetitions)] //! A sprite-sheet animation plugin for [bevy](https://bevyengine.org) //! //! ## Usage //! //! 1. Add the [`AnimationPlugin`] plugin //! //! ```no_run //! use std::time::Duration; //! use bevy::prelude::*; //! use benimator::*; //! //! fn main() { //! App::build() //! .add_plugins(DefaultPlugins) //! .add_plugin(AnimationPlugin) // <-- Enable sprite-sheet animations //! .add_startup_system(spawn.system()) //! // ... //! .run() //! } //! //! fn spawn() { /* ... */ } //! ``` //! //! 2. Insert the [`SpriteSheetAnimation`] component to the sprite sheets you want to animate //! //! ``` //! # use std::time::Duration; //! # use bevy::prelude::*; //! # use benimator::*; //! //! fn spawn(mut commands: Commands) { //! commands //! .spawn_bundle(SpriteSheetBundle { //! // TODO: Configure the sprite sheet //! ..Default::default() //! }) //! // Insert the animation component //! .insert(SpriteSheetAnimation::from_range( //! 0..=2, // Indices of the sprite atlas //! Duration::from_secs_f64(1.0 / 12.0), // Duration of each frame //! )) //! // Start the animation immediately //! .insert(Play); //! } //! ``` //! //! ## Run the animation only once //! //! By default the animation loops forever. But it is possible to configure it differently: //! //! ``` //! # use std::time::Duration; //! # use bevy::prelude::*; //! # use benimator::*; //! # fn spawn(mut commands: Commands) { //! commands //! .spawn_bundle(SpriteSheetBundle { ..Default::default() }) //! .insert( //! SpriteSheetAnimation::from_range(0..=2, Duration::from_millis(100)) //! .once() // <-- Runs the animation only once //! ) //! .insert(Play); // <-- This component will be automatically removed once the animation is finished //! # } //! ``` //! //! ## Play/Pause //! //! Animations proceed only if the [`Play`] component is in the entity. //! //! To pause or resume an animation, simply remove/insert the [`Play`] component. //! //! ## Fine-grained frame-duration //! //! For more precise configuration, it is possible to define the duration of each frame: //! //! ```rust //! # use benimator::*; //! # use std::time::Duration; //! SpriteSheetAnimation::from_frames(vec![ //! Frame::new(0, Duration::from_millis(120)), //! Frame::new(1, Duration::from_millis(100)), //! Frame::new(2, Duration::from_millis(80)), //! ]); //! ``` //! #[cfg(test)] #[macro_use] extern crate rstest; use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; pub use animation::{AnimationMode, Frame, SpriteSheetAnimation}; mod animation; mod state; /// Plugin to enable sprite-sheet animation /// /// See crate level documentation for usage #[derive(Default)] pub struct AnimationPlugin; /// Labels of systems that run during the post-update stage #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, SystemLabel)] pub enum AnimationPostUpdateSystem { /// System that update the sprite atlas textures Animate, } /// Components that indicates the animation is playing /// /// Insert the components to play the animation, and remove it to pause it. /// /// If the animation mode is [`AnimationMode::Once`] this component is automatically removed at the end of the animation. #[derive(Debug, Copy, Clone, Default, Reflect)] #[reflect(Component)] pub struct Play; impl Plugin for AnimationPlugin { fn build(&self, app: &mut AppBuilder) { app.register_type::<SpriteSheetAnimation>() .add_system_set(state::update_systems()) .add_system_to_stage(CoreStage::PostUpdate, state::post_update_system()); } }