Skip to content

Commit

Permalink
Remove action consuming (#582)
Browse files Browse the repository at this point in the history
  • Loading branch information
alice-i-cecile authored Aug 8, 2024
1 parent bc2ba68 commit e8d4da4
Show file tree
Hide file tree
Showing 5 changed files with 4 additions and 282 deletions.
2 changes: 2 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ Input processors allow you to create custom logic for axis-like input manipulati
- removed the `no_ui_priority` feature. To get this behavior, now just turn off the default `ui` feature
- removed the `orientation` module, migrating to `bevy_math::Rot2`
- use the types provided in `bevy_math` instead
- remove action consuming (and various `consume` / `consumed` methods) to reduce complexity and avoid confusing overlap with action disabling
- write your own logic for cases where this was used: generally by working off of `ActionDiff` events that are consumed

### Migration Guide (0.15)

Expand Down
135 changes: 0 additions & 135 deletions examples/consuming_actions.rs

This file was deleted.

13 changes: 1 addition & 12 deletions src/action_state/action_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@ impl ActionData {
data.state.tick();

#[cfg(feature = "timing")]
// Durations should not advance while actions are consumed
if !data.consumed {
data.timing.tick(_current_instant, _previous_instant);
}
data.timing.tick(_current_instant, _previous_instant);
}
ActionKindData::Axis(ref mut _data) => {}
ActionKindData::DualAxis(ref mut _data) => {}
Expand Down Expand Up @@ -117,11 +114,6 @@ pub struct ButtonData {
/// When was the button pressed / released, and how long has it been held for?
#[cfg(feature = "timing")]
pub timing: Timing,
/// Was this action consumed by [`ActionState::consume`](super::ActionState::consume)?
///
/// Actions that are consumed cannot be pressed again until they are explicitly released.
/// This ensures that consumed actions are not immediately re-pressed by continued inputs.
pub consumed: bool,
}

impl ButtonData {
Expand All @@ -132,7 +124,6 @@ impl ButtonData {
fixed_update_state: ButtonState::JustPressed,
#[cfg(feature = "timing")]
timing: Timing::NEW,
consumed: false,
};

/// The default data for a button that was just released.
Expand All @@ -142,7 +133,6 @@ impl ButtonData {
fixed_update_state: ButtonState::JustReleased,
#[cfg(feature = "timing")]
timing: Timing::NEW,
consumed: false,
};

/// The default data for a button that is released,
Expand All @@ -156,7 +146,6 @@ impl ButtonData {
fixed_update_state: ButtonState::Released,
#[cfg(feature = "timing")]
timing: Timing::NEW,
consumed: false,
};

/// Is the action currently pressed?
Expand Down
73 changes: 0 additions & 73 deletions src/action_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,11 +591,6 @@ impl<A: Actionlike> ActionState<A> {

let action_data = self.button_data_mut_or_default(action);

// Consumed actions cannot be pressed until they are released
if action_data.consumed {
return;
}

#[cfg(feature = "timing")]
if action_data.state.released() {
action_data.timing.flip();
Expand All @@ -614,9 +609,6 @@ impl<A: Actionlike> ActionState<A> {

let action_data = self.button_data_mut_or_default(action);

// Once released, consumed actions can be pressed again
action_data.consumed = false;

#[cfg(feature = "timing")]
if action_data.state.pressed() {
action_data.timing.flip();
Expand Down Expand Up @@ -651,71 +643,6 @@ impl<A: Actionlike> ActionState<A> {
}
}

/// Consumes the `action`
///
/// The action will be released, and will not be able to be pressed again
/// until it would have otherwise been released by [`ActionState::release`],
/// [`ActionState::reset`], [`ActionState::reset_all`] or [`ActionState::update`].
///
/// No initial instant will be recorded
/// Instead, this is set through [`ActionState::tick()`]
///
/// # Example
///
/// ```rust
/// use bevy::prelude::Reflect;
/// use leafwing_input_manager::prelude::*;
///
/// #[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
/// enum Action {
/// Eat,
/// Sleep,
/// }
///
/// let mut action_state = ActionState::<Action>::default();
///
/// action_state.press(&Action::Eat);
/// assert!(action_state.pressed(&Action::Eat));
///
/// // Consuming actions releases them
/// action_state.consume(&Action::Eat);
/// assert!(action_state.released(&Action::Eat));
///
/// // Doesn't work, as the action was consumed
/// action_state.press(&Action::Eat);
/// assert!(action_state.released(&Action::Eat));
///
/// // Releasing consumed actions allows them to be pressed again
/// action_state.release(&Action::Eat);
/// action_state.press(&Action::Eat);
/// assert!(action_state.pressed(&Action::Eat));
/// ```
#[inline]
pub fn consume(&mut self, action: &A) {
let action_data = self.button_data_mut_or_default(action);

// This is the only difference from action_state.release(&action)
action_data.consumed = true;
action_data.state.release();
#[cfg(feature = "timing")]
action_data.timing.flip();
}

/// Consumes all actions
#[inline]
pub fn consume_all(&mut self) {
for action in self.keys() {
self.consume(&action);
}
}

/// Is this `action` currently consumed?
#[inline]
#[must_use]
pub fn consumed(&self, action: &A) -> bool {
matches!(self.button_data(action), Some(action_data) if action_data.consumed)
}

/// Is the entire [`ActionState`] currently disabled?
pub fn disabled(&self) -> bool {
self.disabled
Expand Down
63 changes: 1 addition & 62 deletions tests/fixed_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bevy::time::TimeUpdateStrategy;
use bevy::MinimalPlugins;
use leafwing_input_manager::action_state::ActionState;
use leafwing_input_manager::input_map::InputMap;
use leafwing_input_manager::plugin::{InputManagerPlugin, InputManagerSystem};
use leafwing_input_manager::plugin::InputManagerPlugin;
use leafwing_input_manager::prelude::Buttonlike;
use leafwing_input_manager_macros::Actionlike;
use std::time::Duration;
Expand Down Expand Up @@ -205,64 +205,3 @@ fn frame_with_two_fixed_timestep() {
Duration::from_millis(18)
);
}

/// Check that if the action is consumed in FU1, it will still be consumed in F2.
/// (i.e. consuming is shared between the `FixedMain` and `Main` schedules)
#[test]
fn test_consume_in_fixed_update() {
let mut app = build_app(Duration::from_millis(5), Duration::from_millis(5));

app.add_systems(
FixedPostUpdate,
|mut action: ResMut<ActionState<TestAction>>| {
action.consume(&TestAction::Up);
},
);

KeyCode::ArrowUp.press(app.world_mut());

// Frame 1: the FixedUpdate schedule should run once and the button should be just_pressed only once
app.update();
check_update_just_pressed_count(&mut app, 1);
check_fixed_update_run_count(&mut app, 1);
check_fixed_update_just_pressed_count(&mut app, 1);
reset_counters(&mut app);

// the button should still be consumed, even after we exit the FixedUpdate schedule
assert!(
app.world()
.get_resource::<ActionState<TestAction>>()
.unwrap()
.button_data(&TestAction::Up)
.unwrap()
.consumed,
);
}

/// Check that if the action is consumed in F1, it will still be consumed in FU1.
/// (i.e. consuming is shared between the `FixedMain` and `Main` schedules)
#[test]
fn test_consume_in_update() {
let mut app = build_app(Duration::from_millis(5), Duration::from_millis(5));

KeyCode::ArrowUp.press(app.world_mut());
fn consume_action(mut action: ResMut<ActionState<TestAction>>) {
action.consume(&TestAction::Up);
}

app.add_systems(
PreUpdate,
consume_action.in_set(InputManagerSystem::ManualControl),
);

app.add_systems(FixedUpdate, |action: Res<ActionState<TestAction>>| {
// check that the action is still consumed in the FixedMain schedule
assert!(
action.consumed(&TestAction::Up),
"Action should still be consumed in FixedUpdate"
);
});

// the FixedUpdate schedule should run once
app.update();
}

0 comments on commit e8d4da4

Please sign in to comment.