Skip to content

Commit

Permalink
Consume inputs only for used
Browse files Browse the repository at this point in the history
  • Loading branch information
Shatur committed Nov 2, 2024
1 parent 3d30961 commit b68e325
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 46 deletions.
44 changes: 39 additions & 5 deletions src/input_context/context_instance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::any::{self, TypeId};
use std::{
any::{self, TypeId},
cmp::Ordering,
};

use bevy::{prelude::*, utils::Entry};

Expand Down Expand Up @@ -131,6 +134,9 @@ pub struct ActionBind {
modifiers: Vec<Box<dyn InputModifier>>,
conditions: Vec<Box<dyn InputCondition>>,
bindings: Vec<InputBind>,

/// Consumed inputs during state evaluation.
consume_buffer: Vec<Input>,
}

impl ActionBind {
Expand All @@ -145,6 +151,7 @@ impl ActionBind {
modifiers: Default::default(),
conditions: Default::default(),
bindings: Default::default(),
consume_buffer: Default::default(),
}
}

Expand Down Expand Up @@ -301,7 +308,31 @@ impl ActionBind {
let mut current_tracker = TriggerTracker::new(value);
current_tracker.apply_modifiers(time, &mut binding.modifiers);
current_tracker.apply_conditions(actions, time, &mut binding.conditions);
tracker.merge(current_tracker, self.accumulation);

let current_state = current_tracker.state();
if current_state == ActionState::None {
// Ignore non-active trackers to allow the action to fire even if all
// input-level conditions return `ActionState::None`. This ensures that an
// action-level condition or modifier can still trigger the action.
continue;
}

match current_state.cmp(&tracker.state()) {
Ordering::Less => (),
Ordering::Equal => {
tracker.combine(current_tracker, self.accumulation);
if self.consume_input {
self.consume_buffer.push(binding.input);
}
}
Ordering::Greater => {
tracker.overwrite(current_tracker);
if self.consume_input {
self.consume_buffer.clear();
self.consume_buffer.push(binding.input);
}
}
}
}

tracker.apply_modifiers(time, &mut self.modifiers);
Expand All @@ -314,10 +345,13 @@ impl ActionBind {
let state = tracker.state();
let value = tracker.value().convert(self.dim);

if self.consume_input && state != ActionState::None {
for binding in &self.bindings {
reader.consume(binding.input);
if self.consume_input {
if state != ActionState::None {
for &input in &self.consume_buffer {
reader.consume(input);
}
}
self.consume_buffer.clear();
}

action.update(time, state, value);
Expand Down
73 changes: 32 additions & 41 deletions src/input_context/trigger_tracker.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::cmp::Ordering;

use bevy::prelude::*;

use super::{
Expand Down Expand Up @@ -118,47 +116,40 @@ impl TriggerTracker {
self.events_blocked
}

/// Merges input-level tracker into an action-level tracker.
pub(super) fn merge(&mut self, other: Self, accumulation: Accumulation) {
let other_state = other.state();
if other_state == ActionState::None {
// Don't merge non-active trackers to allow the action to fire even if all
// input-level conditions return `ActionState::None`. This ensures that an
// action-level condition or modifier can still trigger the action.
return;
}
/// Replaces the state with `other`.
///
/// Preserves the value dimention.
pub(super) fn overwrite(&mut self, other: TriggerTracker) {
let dim = self.value.dim();
*self = other;
self.value = self.value.convert(dim);
}

match self.state().cmp(&other_state) {
Ordering::Less => {
let dim = self.value.dim();
*self = other;
self.value = self.value.convert(dim);
}
Ordering::Equal => {
let accumulated = match accumulation {
Accumulation::MaxAbs => {
let mut value = self.value.as_axis3d().to_array();
let other_value = other.value.as_axis3d().to_array();
for (axis, other_axis) in value.iter_mut().zip(other_value) {
if axis.abs() < other_axis.abs() {
*axis = other_axis;
}
}
value.into()
/// Merges two trackers.
///
/// Preserves the value dimention.
pub(super) fn combine(&mut self, other: Self, accumulation: Accumulation) {
let accumulated = match accumulation {
Accumulation::MaxAbs => {
let mut value = self.value.as_axis3d().to_array();
let other_value = other.value.as_axis3d().to_array();
for (axis, other_axis) in value.iter_mut().zip(other_value) {
if axis.abs() < other_axis.abs() {
*axis = other_axis;
}
Accumulation::Cumulative => self.value.as_axis3d() + other.value.as_axis3d(),
};

self.value = ActionValue::Axis3D(accumulated).convert(self.value.dim());
self.found_explicit |= other.found_explicit;
self.any_explicit_fired |= other.any_explicit_fired;
self.found_active |= other.found_active;
self.found_implicit |= other.found_implicit;
self.all_implicits_fired &= other.all_implicits_fired;
self.blocked |= other.blocked;
self.events_blocked |= other.events_blocked;
}
value.into()
}
Ordering::Greater => (),
}
Accumulation::Cumulative => self.value.as_axis3d() + other.value.as_axis3d(),
};

self.value = ActionValue::Axis3D(accumulated).convert(self.value.dim());
self.found_explicit |= other.found_explicit;
self.any_explicit_fired |= other.any_explicit_fired;
self.found_active |= other.found_active;
self.found_implicit |= other.found_implicit;
self.all_implicits_fired &= other.all_implicits_fired;
self.blocked |= other.blocked;
self.events_blocked |= other.events_blocked;
}
}

0 comments on commit b68e325

Please sign in to comment.