Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Shute052 committed Feb 18, 2024
1 parent 898d358 commit d5f2cb1
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 206 deletions.
14 changes: 7 additions & 7 deletions src/action_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl<A: Actionlike> ActionState<A> {
/// Updates the [`ActionState`] based on a vector of [`ActionData`], ordered by [`Actionlike::id`](Actionlike).
///
/// The `action_data` is typically constructed from [`InputMap::which_pressed`](crate::input_map::InputMap),
/// which reads from the assorted [`Input`](bevy::input::ButtonInput) resources.
/// which reads from the assorted [`ButtonInput`](bevy::input::ButtonInput) resources.
pub fn update(&mut self, action_data: HashMap<A, ActionData>) {
for (action, action_datum) in action_data {
match self.action_data.entry(action) {
Expand Down Expand Up @@ -263,8 +263,7 @@ impl<A: Actionlike> ActionState<A> {
/// Consider clamping this to account for multiple triggering inputs,
/// typically using the [`clamped_axis_pair`](Self::clamped_axis_pair) method instead.
pub fn axis_pair(&self, action: &A) -> Option<DualAxisData> {
let action_data = self.action_data(action)?;
action_data.axis_pair
self.action_data(action)?.axis_pair
}

/// Get the [`DualAxisData`] associated with the corresponding `action`, clamped to `[-1.0, 1.0]`.
Expand Down Expand Up @@ -443,8 +442,10 @@ impl<A: Actionlike> ActionState<A> {
#[inline]
#[must_use]
pub fn released(&self, action: &A) -> bool {
self.action_data(action)
.map_or(true, |action_data| action_data.state.released())
match self.action_data(action) {
Some(action_data) => action_data.state.released(),
None => true,
}
}

/// Was this `action` released since the last time [tick](ActionState::tick) was called?
Expand Down Expand Up @@ -505,8 +506,7 @@ impl<A: Actionlike> ActionState<A> {
///
/// This will also be [`None`] if the action was never pressed or released.
pub fn instant_started(&self, action: &A) -> Option<Instant> {
let action_data = self.action_data(action)?;
action_data.timing.instant_started
self.action_data(action)?.timing.instant_started
}

/// The [`Duration`] for which the action has been held or released
Expand Down
67 changes: 32 additions & 35 deletions src/axislike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,10 +685,7 @@ impl DualAxisData {
#[inline]
pub fn direction(&self) -> Option<Direction> {
// TODO: replace this quick-n-dirty hack once Direction::new no longer panics
if self.xy.length() > 0.00001 {
return Some(Direction::new(self.xy));
}
None
(self.xy.length() > 0.00001).then(|| Direction::new(self.xy))
}

/// The [`Rotation`] (measured clockwise from midnight) that this axis is pointing towards, if any
Expand All @@ -697,10 +694,7 @@ impl DualAxisData {
#[must_use]
#[inline]
pub fn rotation(&self) -> Option<Rotation> {
match Rotation::from_xy(self.xy) {
Ok(rotation) => Some(rotation),
Err(_) => None,
}
Rotation::from_xy(self.xy).ok()
}

/// How far from the origin is this axis's position?
Expand Down Expand Up @@ -793,57 +787,60 @@ impl std::hash::Hash for DeadZoneShape {
impl DeadZoneShape {
/// Computes the input value based on the deadzone.
pub fn deadzone_input_value(&self, x: f32, y: f32) -> Option<DualAxisData> {
let value = Vec2::new(x, y);

match self {
DeadZoneShape::Cross {
horizontal_width,
vertical_width,
} => self.cross_deadzone_value(value, *horizontal_width, *vertical_width),
} => self.cross_deadzone_value(x, y, *horizontal_width, *vertical_width),
DeadZoneShape::Ellipse { radius_x, radius_y } => {
self.ellipse_deadzone_value(value, *radius_x, *radius_y)
self.ellipse_deadzone_value(x, y, *radius_x, *radius_y)
}
}
}

/// Computes the input value based on the cross deadzone.
fn cross_deadzone_value(
&self,
value: Vec2,
x: f32,
y: f32,
horizontal_width: f32,
vertical_width: f32,
) -> Option<DualAxisData> {
let new_x = f32::from(value.x.abs() > vertical_width) * value.x;
let new_y = f32::from(value.y.abs() > horizontal_width) * value.y;
let new_value = Vec2::new(new_x, new_y);

if new_value == Vec2::ZERO {
None
} else {
let scaled_value =
Self::scale_value(new_value, Vec2::new(vertical_width, horizontal_width));
Some(DualAxisData::from_xy(scaled_value))
}
let new_x = deadzone_axis_value(x, vertical_width);
let new_y = deadzone_axis_value(y, horizontal_width);
let is_outside_deadzone = new_x != 0.0 || new_y != 0.0;
is_outside_deadzone.then(|| DualAxisData::new(new_x, new_y))
}

/// Computes the input value based on the ellipse deadzone.
fn ellipse_deadzone_value(
&self,
value: Vec2,
x: f32,
y: f32,
radius_x: f32,
radius_y: f32,
) -> Option<DualAxisData> {
let clamped_radius_x = radius_x.max(f32::EPSILON);
let clamped_radius_y = radius_y.max(f32::EPSILON);
if (value.x / clamped_radius_x).powi(2) + (value.y / clamped_radius_y).powi(2) < 1.0 {
return None;
}

let scaled_value = Self::scale_value(value, Vec2::new(radius_x, radius_y));
Some(DualAxisData::from_xy(scaled_value))
let normalized_x = x / radius_x.max(f32::EPSILON);
let normalized_y = y / radius_y.max(f32::EPSILON);
let is_outside_deadzone = normalized_x.powi(2) + normalized_y.powi(2) >= 1.0;
is_outside_deadzone.then(|| {
let new_x = deadzone_axis_value(x, radius_x);
let new_y = deadzone_axis_value(y, radius_y);
DualAxisData::new(new_x, new_y)
})
}
}

fn scale_value(value: Vec2, deadzone_size: Vec2) -> Vec2 {
value.signum() * (value.abs() - deadzone_size).max(Vec2::ZERO) / (1.0 - deadzone_size)
/// Applies the given deadzone to the axis value.
///
/// Returns 0.0 if the axis value is within the deadzone.
/// Otherwise, returns the normalized axis value between -1.0 and 1.0.
#[inline(always)]
pub(crate) fn deadzone_axis_value(axis_value: f32, deadzone: f32) -> f32 {
let abs_axis_value = axis_value.abs();
if abs_axis_value <= deadzone {
0.0
} else {
axis_value.signum() * (abs_axis_value - deadzone) / (1.0 - deadzone)
}
}
44 changes: 13 additions & 31 deletions src/clashing_inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ impl<A: Actionlike> InputMap<A> {
pub(crate) fn possible_clashes(&self) -> Vec<Clash<A>> {
let mut clashes = Vec::default();

for (action_a, _) in self.iter() {
for (action_b, _) in self.iter() {
for action_a in self.actions() {
for action_b in self.actions() {
if let Some(clash) = self.possible_clash(action_a, action_b) {
clashes.push(clash);
}
Expand Down Expand Up @@ -162,11 +162,7 @@ impl<A: Actionlike> InputMap<A> {
}
}

if !clash.inputs_a.is_empty() {
Some(clash)
} else {
None
}
(!clash.inputs_a.is_empty()).then_some(clash)
}
}

Expand Down Expand Up @@ -196,22 +192,13 @@ impl<A: Actionlike> Clash<A> {
// Does the `button` clash with the `chord`?
#[must_use]
fn button_chord_clash(button: &InputKind, chord: &[InputKind]) -> bool {
if chord.len() <= 1 {
return false;
}

chord.contains(button)
chord.len() > 1 && chord.contains(button)
}

// Does the `dpad` clash with the `chord`?
#[must_use]
fn dpad_chord_clash(dpad: &VirtualDPad, chord: &[InputKind]) -> bool {
if chord.len() <= 1 {
return false;
}
[dpad.up, dpad.down, dpad.left, dpad.right]
.iter()
.any(|button| chord.contains(button))
chord.len() > 1 && chord.iter().any(|button| dpad_button_clash(dpad, button))
}

fn dpad_button_clash(dpad: &VirtualDPad, button: &InputKind) -> bool {
Expand All @@ -223,7 +210,7 @@ fn dpad_button_clash(dpad: &VirtualDPad, button: &InputKind) -> bool {
fn dpad_dpad_clash(dpad1: &VirtualDPad, dpad2: &VirtualDPad) -> bool {
let iter1 = [&dpad1.up, &dpad1.down, &dpad1.left, &dpad1.right].into_iter();
let iter2 = [&dpad2.up, &dpad2.down, &dpad2.left, &dpad2.right].into_iter();
iter1.zip(iter2).any(|(left, right)| *left == *right)
iter1.zip(iter2).any(|(left, right)| left == right)
}

#[must_use]
Expand All @@ -235,24 +222,21 @@ fn virtual_axis_button_clash(axis: &VirtualAxis, button: &InputKind) -> bool {
fn virtual_axis_dpad_clash(axis: &VirtualAxis, dpad: &VirtualDPad) -> bool {
[&dpad.up, &dpad.down, &dpad.left, &dpad.right]
.iter()
.any(|button| **button == axis.negative || **button == axis.positive)
.any(|button| virtual_axis_button_clash(axis, button))
}

#[must_use]
fn virtual_axis_chord_clash(axis: &VirtualAxis, chord: &[InputKind]) -> bool {
if chord.len() <= 1 {
return false;
}

chord.contains(&axis.negative) || chord.contains(&axis.positive)
chord.len() > 1
&& chord
.iter()
.any(|button| virtual_axis_button_clash(axis, button))
}

#[must_use]
fn virtual_axis_virtual_axis_clash(axis1: &VirtualAxis, axis2: &VirtualAxis) -> bool {
axis1.negative == axis2.negative
|| axis1.negative == axis2.positive
|| axis1.positive == axis2.negative
|| axis1.positive == axis2.positive
virtual_axis_button_clash(axis1, &axis2.negative)
|| virtual_axis_button_clash(axis1, &axis2.positive)
}

/// Does the `chord_a` clash with `chord_b`?
Expand All @@ -266,8 +250,6 @@ fn chord_chord_clash(chord_a: &Vec<InputKind>, chord_b: &Vec<InputKind>) -> bool
return false;
}

// Since Chords typically have a few elements,
// making slice-based checks more efficient than set-based ones.
fn is_subset(slice_a: &[InputKind], slice_b: &[InputKind]) -> bool {
slice_a.iter().all(|a| slice_b.contains(a))
}
Expand Down
10 changes: 2 additions & 8 deletions src/display_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::axislike::{VirtualAxis, VirtualDPad};
use crate::user_input::{InputKind, UserInput};
use itertools::Itertools;
use std::fmt::Display;

impl Display for UserInput {
Expand All @@ -10,14 +11,7 @@ impl Display for UserInput {
// The representation of the button
UserInput::Single(button) => write!(f, "{button}"),
// The representation of each button, separated by "+"
UserInput::Chord(button_set) => {
let mut string = String::default();
for button in button_set.iter() {
string.push('+');
string.push_str(&button.to_string());
}
write!(f, "{string}")
}
UserInput::Chord(button_set) => f.write_str(&button_set.iter().join("+")),
UserInput::VirtualDPad(VirtualDPad {
up,
down,
Expand Down
16 changes: 6 additions & 10 deletions src/input_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,10 @@ impl<A: Actionlike> InputMap<A> {
pub fn iter(&self) -> impl Iterator<Item = (&A, &Vec<UserInput>)> {
self.map.iter()
}
/// Returns an iterator over actions
pub(crate) fn actions(&self) -> impl Iterator<Item = &A> {
self.map.keys()
}
/// Returns a reference to the inputs mapped to `action`
#[must_use]
pub fn get(&self, action: &A) -> Option<&Vec<UserInput>> {
Expand All @@ -372,11 +376,7 @@ impl<A: Actionlike> InputMap<A> {
/// How many input bindings are registered total?
#[must_use]
pub fn len(&self) -> usize {
let mut i = 0;
for inputs in self.map.values() {
i += inputs.len();
}
i
self.map.values().map(|inputs| inputs.len()).sum()
}

/// Are any input bindings registered at all?
Expand Down Expand Up @@ -406,11 +406,7 @@ impl<A: Actionlike> InputMap<A> {
/// Returns `Some(input)` if found.
pub fn remove_at(&mut self, action: &A, index: usize) -> Option<UserInput> {
let input_vec = self.map.get_mut(action)?;
if input_vec.len() <= index {
None
} else {
Some(input_vec.remove(index))
}
(input_vec.len() > index).then(|| input_vec.remove(index))
}

/// Removes the input for the `action`, if it exists
Expand Down
Loading

0 comments on commit d5f2cb1

Please sign in to comment.