diff --git a/CHANGELOG.md b/CHANGELOG.md index f57a5be..cf1bf97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rename `Pressed` into `Press`. - Rename `BlockedBy` into `BlockBy`. - Rename `Scalar` into `Scale`. +- Split `ActionData::update` into `ActionData::update_time`, `ActionData::trigger_events` and `ActionData::set_state`. - Use `isize` for `InputContext::PRIORITY`. - Replace `SmoothDelta` with `LerpDelta` that does only linear interpolation. Using easing functions for inputs doesn't make much sense. - Modifiers are now allowed to change passed value dimensions. @@ -35,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ignore_incompatible!` since no longer needed. - `SwizzleAxis::XXX`, `SwizzleAxis::YYY` and `SwizzleAxis::ZZZ`. They encourage a bad pattern of defining actions with duplicate data. Duplicate axes inside the trigger if needed. +- `ActionData::trigger_removed`, use `ActionData::trigger_events` instead. ## [0.1.0] - 2024-10-20 diff --git a/src/input_context/context_instance.rs b/src/input_context/context_instance.rs index f68d6bc..8747127 100644 --- a/src/input_context/context_instance.rs +++ b/src/input_context/context_instance.rs @@ -11,6 +11,7 @@ use super::{ use crate::{ action_value::{ActionValue, ActionValueDim}, input::{input_reader::InputReader, GamepadDevice, Input}, + ActionState, }; /// Instance for [`InputContext`](super::InputContext). @@ -95,7 +96,13 @@ impl ContextInstance { .actions .get(&binding.type_id) .expect("actions and bindings should have matching type IDs"); - action.trigger_removed(commands, entities, binding.dim); + + action.trigger_events( + commands, + entities, + ActionState::None, + ActionValue::zero(binding.dim), + ); } } } @@ -298,7 +305,9 @@ impl ActionBind { let state = tracker.state(); let value = tracker.value().convert(self.dim); - action.update(commands, time, entities, state, value); + action.update_time(time); + action.trigger_events(commands, entities, state, value); + action.set_state(state); } } diff --git a/src/input_context/input_action.rs b/src/input_context/input_action.rs index 7c83a65..45a946f 100644 --- a/src/input_context/input_action.rs +++ b/src/input_context/input_action.rs @@ -47,21 +47,14 @@ impl ActionData { state: Default::default(), elapsed_secs: 0.0, fired_secs: 0.0, - trigger_events: Self::trigger::, + trigger_events: Self::trigger_events_typed::, } } - /// Updates internal state and triggers corresponding events. - pub fn update( - &mut self, - commands: &mut Commands, - time: &Time, - entities: &[Entity], - state: ActionState, - value: impl Into, - ) { - // Add time from the previous frame if needed - // before triggering events. + /// Adds time from the previous frame if needed + /// + /// Should be called before [`Self::trigger_events`]. + pub fn update_time(&mut self, time: &Time) { match self.state { ActionState::None => (), ActionState::Ongoing => { @@ -72,11 +65,27 @@ impl ActionData { self.fired_secs += time.delta_seconds(); } } + } + /// Triggers events for transitioning from the current state to the specified `state`. + /// + /// Should be called after [`Self::update_time`] and before [`Self::set_state`]. + pub fn trigger_events( + &self, + commands: &mut Commands, + entities: &[Entity], + state: ActionState, + value: impl Into, + ) { (self.trigger_events)(self, commands, entities, state, value.into()); - self.state = state; + } + /// Sets state and resets time if necessary. + /// + /// Should be called after [`Self::trigger_events`]. + pub fn set_state(&mut self, state: ActionState) { // Reset time for updated state. + self.state = state; match self.state { ActionState::None => { self.elapsed_secs = 0.0; @@ -89,29 +98,7 @@ impl ActionData { } } - /// Trigger events for removed entities. - /// - /// This will trigger transition from the current state to [`ActionState::None`] - /// simulating releasing the input. - /// - /// Internal state won't be updated. - /// Called for removed entities for shared contexts or for context removals. - pub fn trigger_removed( - &self, - commands: &mut Commands, - entities: &[Entity], - dim: ActionValueDim, - ) { - (self.trigger_events)( - self, - commands, - entities, - ActionState::None, - ActionValue::zero(dim), - ); - } - - fn trigger( + fn trigger_events_typed( &self, commands: &mut Commands, entities: &[Entity], diff --git a/src/input_context/input_condition/block_by.rs b/src/input_context/input_condition/block_by.rs index bf88ade..2ec5beb 100644 --- a/src/input_context/input_condition/block_by.rs +++ b/src/input_context/input_condition/block_by.rs @@ -70,11 +70,10 @@ mod tests { fn block() { let mut condition = BlockBy::::default(); let mut action = ActionData::new::(); - let mut world = World::new(); - let time = Time::default(); - action.update(&mut world.commands(), &time, &[], ActionState::Fired, true); + action.set_state(ActionState::Fired); let mut actions = ActionsData::default(); actions.insert_action::(action); + let time = Time::default(); assert_eq!( condition.evaluate(&actions, &time, true.into()), diff --git a/src/input_context/input_condition/chord.rs b/src/input_context/input_condition/chord.rs index d6de95e..b2b9f23 100644 --- a/src/input_context/input_condition/chord.rs +++ b/src/input_context/input_condition/chord.rs @@ -71,11 +71,10 @@ mod tests { fn chord() { let mut condition = Chord::::default(); let mut action = ActionData::new::(); - let mut world = World::new(); - let time = Time::default(); - action.update(&mut world.commands(), &time, &[], ActionState::Fired, true); + action.set_state(ActionState::Fired); let mut actions = ActionsData::default(); actions.insert_action::(action); + let time = Time::default(); assert_eq!( condition.evaluate(&actions, &time, true.into()),