leafwing_input_manager/
axislike.rs

1//! Tools for working with directional axis-like user inputs (game sticks, D-Pads and emulated equivalents)
2
3use bevy::prelude::{Reflect, Vec2};
4use serde::{Deserialize, Serialize};
5
6/// The directions for single-axis inputs.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
8#[must_use]
9pub enum AxisDirection {
10    /// Negative direction.
11    Negative,
12
13    /// Positive direction.
14    Positive,
15}
16
17impl AxisDirection {
18    /// Returns the full active value along an axis.
19    #[must_use]
20    #[inline]
21    pub fn full_active_value(&self) -> f32 {
22        match self {
23            Self::Negative => -1.0,
24            Self::Positive => 1.0,
25        }
26    }
27
28    /// Checks if the given `value` represents an active input in this direction,
29    /// considering the specified `threshold`.
30    ///
31    /// # Requirements
32    ///
33    /// - `threshold` >= `0.0`.
34    ///
35    /// # Panics
36    ///
37    /// Panics if the requirement isn't met.
38    #[must_use]
39    #[inline]
40    pub fn is_active(&self, value: f32, threshold: f32) -> bool {
41        assert!(threshold >= 0.0);
42        match self {
43            Self::Negative => value < -threshold,
44            Self::Positive => value > threshold,
45        }
46    }
47}
48
49/// An axis for dual-axis inputs.
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
51#[must_use]
52pub enum DualAxisType {
53    /// The X-axis (typically horizontal movement).
54    X,
55
56    /// The Y-axis (typically vertical movement).
57    Y,
58}
59
60impl DualAxisType {
61    /// Returns both X and Y axes.
62    #[inline]
63    pub const fn axes() -> [Self; 2] {
64        [Self::X, Self::Y]
65    }
66
67    /// Returns the positive and negative [`DualAxisDirection`]s for the current axis.
68    #[inline]
69    pub const fn directions(&self) -> [DualAxisDirection; 2] {
70        [self.negative(), self.positive()]
71    }
72
73    /// Returns the negative [`DualAxisDirection`] for the current axis.
74    #[inline]
75    pub const fn negative(&self) -> DualAxisDirection {
76        match self {
77            Self::X => DualAxisDirection::Left,
78            Self::Y => DualAxisDirection::Down,
79        }
80    }
81
82    /// Returns the positive [`DualAxisDirection`] for the current axis.
83    #[inline]
84    pub const fn positive(&self) -> DualAxisDirection {
85        match self {
86            Self::X => DualAxisDirection::Right,
87            Self::Y => DualAxisDirection::Up,
88        }
89    }
90
91    /// Returns the value along the current axis.
92    #[must_use]
93    #[inline]
94    pub const fn get_value(&self, value: Vec2) -> f32 {
95        match self {
96            Self::X => value.x,
97            Self::Y => value.y,
98        }
99    }
100
101    /// Creates a [`Vec2`] with the specified `value` on this axis and `0.0` on the other.
102    #[must_use]
103    #[inline]
104    pub const fn dual_axis_value(&self, value: f32) -> Vec2 {
105        match self {
106            Self::X => Vec2::new(value, 0.0),
107            Self::Y => Vec2::new(0.0, value),
108        }
109    }
110}
111
112/// The directions for dual-axis inputs.
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
114#[must_use]
115pub enum DualAxisDirection {
116    /// Upward direction.
117    Up,
118
119    /// Downward direction.
120    Down,
121
122    /// Leftward direction.
123    Left,
124
125    /// Rightward direction.
126    Right,
127}
128
129impl DualAxisDirection {
130    /// Returns the [`DualAxisType`] associated with this direction.
131    #[inline]
132    pub fn axis(&self) -> DualAxisType {
133        match self {
134            Self::Up => DualAxisType::Y,
135            Self::Down => DualAxisType::Y,
136            Self::Left => DualAxisType::X,
137            Self::Right => DualAxisType::X,
138        }
139    }
140
141    /// Returns the [`AxisDirection`] (positive or negative) on the axis.
142    #[inline]
143    pub fn axis_direction(&self) -> AxisDirection {
144        match self {
145            Self::Up => AxisDirection::Positive,
146            Self::Down => AxisDirection::Negative,
147            Self::Left => AxisDirection::Negative,
148            Self::Right => AxisDirection::Positive,
149        }
150    }
151
152    /// Returns the full active value along both axes.
153    #[must_use]
154    #[inline]
155    pub fn full_active_value(&self) -> Vec2 {
156        match self {
157            Self::Up => Vec2::Y,
158            Self::Down => Vec2::NEG_Y,
159            Self::Left => Vec2::NEG_X,
160            Self::Right => Vec2::X,
161        }
162    }
163
164    /// Checks if the given `value` represents an active input in this direction,
165    /// considering the specified `threshold`.
166    ///
167    /// # Requirements
168    ///
169    /// - `threshold` >= `0.0`.
170    ///
171    /// # Panics
172    ///
173    /// Panics if the requirement isn't met.
174    #[must_use]
175    #[inline]
176    pub fn is_active(&self, value: Vec2, threshold: f32) -> bool {
177        let axis_value = self.axis().get_value(value);
178        self.axis_direction().is_active(axis_value, threshold)
179    }
180}