Game stats that reset every frame, inspired by immediate mode GUI.
gamedev bevy stats
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #7 from AlephCubed/dev

Final pass on docs and example.

authored by

AlephCubed and committed by
GitHub
9d9911c7 ec4ddfdd

+53 -32
+8 -3
README.md
··· 4 4 5 5 This makes it easy to implement temporary buffs/debuffs, and effects that change over time. 6 6 Using a derive macro, stat resets are propagated to any stat fields, 7 - making it easy to compose stats into more complex or specific objects. 7 + making it easy to compose stats into more complex objects. 8 8 9 9 ```rust 10 10 #[derive(StatContainer)] ··· 16 16 loop { 17 17 speed.0 *= 2.0; // Applies a multiplier to the final result. 18 18 speed.0 += 5; // Adds a bonus to the final result. 19 - // The order does not matter. Bonuses are always applied before multipliers. 19 + // The order does not matter, bonuses are always applied before multipliers. 20 20 assert_eq!(speed.0.total(), 30); // (10 + 5) * 2 = 30 21 21 22 22 speed.reset_modifiers(); // Reset bonus and multiplier, so speed is back to 10. ··· 27 27 ## Bevy 28 28 29 29 There is build-in integration with the [Bevy Engine](https://bevyengine.org) via the `bevy` feature flag. 30 - This adds systems for resetting `StatContainer` components and resources. 30 + This adds plugins for resetting `StatContainer` components and resources. 31 31 32 32 ```rust 33 33 #[derive(StatContainer, Component, Resource)] ··· 36 36 fn main() { 37 37 App::new() 38 38 .add_plugins(( 39 + ImmediateStatsPlugin, 39 40 ResetComponentPlugin::<Speed>::new(), 40 41 ResetResourcePlugin::<Speed>::new(), 41 42 )) ··· 50 51 or the existing `insert_resource` macro. 51 52 52 53 ```rust 54 + fn main() { 55 + App::new().add_plugins((ImmediateStatsPlugin, MyPlugin)).run(); 56 + } 57 + 53 58 #[butler_plugin] 54 59 struct MyPlugin; 55 60
+17 -12
immediate_stats/examples/simple_bevy.rs
··· 5 5 use immediate_stats::*; 6 6 7 7 fn main() { 8 - App::new().add_plugins((MinimalPlugins, SpeedPlugin)).run(); 8 + App::new() 9 + .add_plugins((MinimalPlugins, ImmediateStatsPlugin, SpeedPlugin)) 10 + .run(); 9 11 } 10 12 11 13 struct SpeedPlugin; 12 14 13 15 impl Plugin for SpeedPlugin { 14 16 fn build(&self, app: &mut App) { 15 - app.add_plugins((ImmediateStatsPlugin, ResetComponentPlugin::<Speed>::new())) 16 - .add_systems(Startup, init_speed) 17 - .add_systems( 18 - Update, 19 - ( 20 - // Modifiers must be applied before the speed can be read. 21 - apply_modifiers.in_set(StatSystems::Modify), 22 - read_speed.in_set(StatSystems::Read), 23 - ), 24 - ); 17 + app.add_plugins( 18 + ResetComponentPlugin::<Speed>::new(), // Reset modifiers, so speed is back to 10. 19 + ) 20 + .add_systems(Startup, init_speed) 21 + .add_systems( 22 + Update, 23 + ( 24 + // Modifiers must be applied before the speed can be read. 25 + apply_modifiers.in_set(StatSystems::Modify), 26 + read_speed.in_set(StatSystems::Read), 27 + ), 28 + ); 25 29 } 26 30 } 27 31 32 + // Implements `reset_modifiers` by passing the call onto `Stat`. 28 33 #[derive(StatContainer, Component)] 29 34 struct Speed(Stat); 30 35 ··· 36 41 for mut speed in &mut speeds { 37 42 speed.0 *= 2.0; // Applies a multiplier to the final result. 38 43 speed.0 += 5; // Adds a bonus to the final result. 39 - // The order does not matter. Bonuses are always applied before multipliers. 44 + // The order does not matter, bonuses are always applied before multipliers. 40 45 } 41 46 } 42 47
+3 -1
immediate_stats/examples/simple_bevy_butler.rs
··· 14 14 #[butler_plugin] 15 15 struct SpeedPlugin; 16 16 17 + // Implements `reset_modifiers` by passing the call onto `Stat`. 18 + // This will also add the `ResetComponentPlugin` to `SpeedPlugin`. 17 19 #[derive(StatContainer, Component)] 18 20 #[add_component(plugin = SpeedPlugin)] 19 21 struct Speed(Stat); ··· 28 30 for mut speed in &mut speeds { 29 31 speed.0 *= 2.0; // Applies a multiplier to the final result. 30 32 speed.0 += 5; // Adds a bonus to the final result. 31 - // The order does not matter. Bonuses are always applied before multipliers. 33 + // The order does not matter, bonuses are always applied before multipliers. 32 34 } 33 35 } 34 36
+2 -1
immediate_stats/examples/simple_main_loop.rs
··· 3 3 4 4 use immediate_stats::*; 5 5 6 + // Implements `reset_modifiers` by passing the call onto `Stat`. 6 7 #[derive(StatContainer)] 7 8 struct Speed(Stat); 8 9 ··· 13 14 // 1. Apply modifiers: 14 15 speed.0 *= 2.0; // Applies a multiplier to the final result. 15 16 speed.0 += 5; // Adds a bonus to the final result. 16 - // The order does not matter. Bonuses are always applied before multipliers. 17 + // The order does not matter, bonuses are always applied before multipliers. 17 18 18 19 // 2. Read total: 19 20 println!("The current speed is {}.", speed.0.total());
+6 -3
immediate_stats/src/bevy.rs
··· 40 40 Read, 41 41 } 42 42 43 - /// Prevents any [`StatContainers`](StatContainer) on an entity from resetting. 43 + /// Prevents all [`StatContainers`](StatContainer) 44 + /// on an entity from getting reset by [`ResetComponentPlugin`]. 44 45 #[derive(Component, Reflect, Eq, PartialEq, Debug, Default, Clone)] 45 46 #[component(storage = "SparseSet")] 46 47 #[reflect(Component, PartialEq, Debug, Default, Clone)] 47 48 pub struct PauseStatReset; 48 49 49 50 /// Calls [`reset_modifiers`](StatContainer::reset_modifiers) on all `T` components. 51 + /// This can be paused on a per-entity basis using the [`PauseStatReset`] component. 50 52 /// 51 - /// Reset occurs in the [`Reset`](StatSystems::Reset) system set during [`PreUpdate`]. 53 + /// Reset occurs in the [`Reset`](StatSystems::Reset) system set during `PreUpdate`. 52 54 pub struct ResetComponentPlugin<T: Component<Mutability = Mutable> + StatContainer> { 53 55 _phantom: PhantomData<T>, 54 56 } ··· 63 65 } 64 66 65 67 /// Calls [`reset_modifiers`](StatContainer::reset_modifiers) on all `T` components. 68 + /// This can be paused on a per-entity basis using the [`PauseStatReset`] component. 66 69 /// 67 70 /// Use the [`ResetResourcePlugin`] for recommended configuration. 68 71 pub fn reset_component_modifiers<T: Component<Mutability = Mutable> + StatContainer>( ··· 90 93 91 94 /// Calls [`reset_modifiers`](StatContainer::reset_modifiers) on the `T` resource, if it exists. 92 95 /// 93 - /// Reset occurs in the [`Reset`](StatSystems::Reset) system set during [`PreUpdate`]. 96 + /// Reset occurs in the [`Reset`](StatSystems::Reset) system set during `PreUpdate`. 94 97 pub struct ResetResourcePlugin<T: Resource + StatContainer> { 95 98 _phantom: PhantomData<T>, 96 99 }
+11 -6
immediate_stats/src/lib.rs
··· 2 2 //! 3 3 //! This makes it easy to implement temporary buffs/debuffs, and effects that change over time. 4 4 //! Using a [derive macro](macro@StatContainer), stat resets are propagated to any stat fields, 5 - //! making it easy to compose stats into more complex or specific objects. 5 + //! making it easy to compose stats into more complex objects. 6 6 //! 7 7 //! ```rust no_run 8 8 //! # use immediate_stats::*; ··· 10 10 //! struct Speed(Stat); 11 11 //! 12 12 //! fn main() { 13 + //! let mut speed = Speed(Stat::new(10)); // Set base speed to 10. 14 + //! 13 15 //! loop { 14 - //! let mut speed = Speed(Stat::new(10)); // Set base speed to 10. 15 - //! 16 16 //! speed.0 *= 2.0; // Applies a multiplier to the final result. 17 17 //! speed.0 += 5; // Adds a bonus to the final result. 18 - //! // The order does not matter. Bonuses are always applied before multipliers. 18 + //! // The order does not matter, bonuses are always applied before multipliers. 19 19 //! assert_eq!(speed.0.total(), 30); // (10 + 5) * 2 = 30 20 20 //! 21 21 //! speed.reset_modifiers(); // Reset speed back to 10. ··· 40 40 //! fn main() { 41 41 //! App::new() 42 42 //! .add_plugins(( 43 + //! ImmediateStatsPlugin, 43 44 //! ResetComponentPlugin::<Speed>::new(), 44 45 //! ResetResourcePlugin::<Speed>::new(), 45 46 //! )) ··· 60 61 //! # use bevy_ecs::prelude::*; 61 62 //! # use immediate_stats::*; 62 63 //! # use bevy_butler::*; 64 + //! fn main() { 65 + //! App::new().add_plugins((ImmediateStatsPlugin, MyPlugin)).run(); 66 + //! } 67 + //! 63 68 //! #[butler_plugin] 64 69 //! struct MyPlugin; 65 70 //! 66 71 //! // `StatContainer` derive adds the `add_component` attribute 67 72 //! // and hooks into the existing `insert_resource` macro. 68 73 //! #[derive(StatContainer, Component, Resource, Default)] 69 - //! #[add_component(plugin = MyPlugin)] // Adds `reset_component_modifiers` system. 70 - //! #[insert_resource(plugin = MyPlugin)] // Adds `reset_resource_modifiers` system. 74 + //! #[add_component(plugin = MyPlugin)] // Adds `ResetComponentPlugin` 75 + //! #[insert_resource(plugin = MyPlugin)] // Adds `ResetResourcePlugin` 71 76 //! struct Speed(Stat); 72 77 //! ``` 73 78 //!
+1 -1
immediate_stats/src/modifier.rs
··· 10 10 reflect(PartialEq, Debug, Clone) 11 11 )] 12 12 pub struct Modifier { 13 - /// Added to `base` of a [`Stat`](super::Stat) during calculation. 13 + /// Added to the `base` of a [`Stat`](super::Stat) during calculation. 14 14 /// 15 15 /// Can be modified using [`+=`](Modifier::add_assign) and [`-=`](`Modifier::sub_assign`). 16 16 pub bonus: i32,
+5 -5
immediate_stats/src/stat.rs
··· 9 9 /// Temporary bonuses can be applied using [`+=`][add], [`-=`][sub], [`*=`][mul], and [`/=`][div]. 10 10 /// During [calculation](Stat::total), 11 11 /// multiplication and division are always applied **after** addition and subtraction. 12 - /// These bonuses are reset when [`reset_modifiers`][reset] is called. 12 + /// These modifiers are reset when [`reset_modifiers`][reset] is called. 13 13 /// 14 14 /// [reset]: StatContainer::reset_modifiers 15 15 /// [add]: Stat::add_assign ··· 26 26 /// The persistent value of the stat. 27 27 /// After being [reset](StatContainer::reset_modifiers), [`Stat::total`] will be equal to `base`. 28 28 pub base: i32, 29 - /// Added to `base` during calculation and gets reset to zero every iteration. 30 - /// This is added *before* `multiplier` is applied. 29 + /// Added to `base` during calculation and gets [reset](StatContainer::reset_modifiers) to zero. 30 + /// This is added **before** `multiplier` is applied. 31 31 /// 32 32 /// Can be modified using [`+=`](Stat::add_assign) or [`-=`](Stat::sub_assign). 33 33 pub bonus: i32, 34 34 /// Multiplies the `base` during calculation and gets reset to one every iteration. 35 - /// This is applied *after* `bonus` is added. 35 + /// This is applied **after** `bonus` is added. 36 36 /// 37 - /// Can be modified using [*=](`Stat::mul_assign`) or [/=](`Stat::div_assign`). 37 + /// Can be modified using [`*=`](`Stat::mul_assign`) or [`/=`](`Stat::div_assign`). 38 38 pub multiplier: f32, 39 39 } 40 40