bevy_enhanced_input/input_modifier/
swizzle_axis.rs

1use bevy::prelude::*;
2
3use super::InputModifier;
4use crate::{action_map::ActionMap, action_value::ActionValue};
5
6/// Swizzle axis components of an input value.
7///
8/// Useful for things like mapping a 1D input onto the Y axis of a 2D action.
9///
10/// It tries to preserve the original dimension. However, if an axis from the original
11/// is promoted to a higher dimension, the value's type changes. Missing axes will be replaced with zero.
12///
13/// For example, [`ActionValue::Bool`] will remain unchanged for [`Self::XZY`] (X in the first place).
14/// But for variants like [`Self::YXZ`] (where X becomes the second component), it will be
15/// converted into [`ActionValue::Axis2D`] with Y set to the value.
16#[derive(Clone, Copy, Debug)]
17pub enum SwizzleAxis {
18    /// Swap X and Y axis. Useful for binding 1D inputs to the Y axis for 2D actions.
19    YXZ,
20    /// Swap X and Z axis.
21    ZYX,
22    /// Swap Y and Z axis.
23    XZY,
24    /// Reorder all axes, Y first.
25    YZX,
26    /// Reorder all axes, Z first.
27    ZXY,
28}
29
30impl InputModifier for SwizzleAxis {
31    fn apply(
32        &mut self,
33        _action_map: &ActionMap,
34        _time: &Time<Virtual>,
35        value: ActionValue,
36    ) -> ActionValue {
37        match value {
38            ActionValue::Bool(value) => {
39                let value = if value { 1.0 } else { 0.0 };
40                self.apply(_action_map, _time, value.into())
41            }
42            ActionValue::Axis1D(value) => match self {
43                SwizzleAxis::YXZ | SwizzleAxis::ZXY => (Vec2::Y * value).into(),
44                SwizzleAxis::ZYX | SwizzleAxis::YZX => (Vec3::Z * value).into(),
45                SwizzleAxis::XZY => value.into(),
46            },
47            ActionValue::Axis2D(value) => match self {
48                SwizzleAxis::YXZ => value.yx().into(),
49                SwizzleAxis::ZYX => (0.0, value.y).into(),
50                SwizzleAxis::XZY => (value.x, 0.0).into(),
51                SwizzleAxis::YZX => (value.y, 0.0).into(),
52                SwizzleAxis::ZXY => (0.0, value.x).into(),
53            },
54            ActionValue::Axis3D(value) => match self {
55                SwizzleAxis::YXZ => value.yxz().into(),
56                SwizzleAxis::ZYX => value.zyx().into(),
57                SwizzleAxis::XZY => value.xzy().into(),
58                SwizzleAxis::YZX => value.yzx().into(),
59                SwizzleAxis::ZXY => value.zxy().into(),
60            },
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn yxz() {
71        let mut modifier = SwizzleAxis::YXZ;
72        let action_map = ActionMap::default();
73        let time = Time::default();
74
75        assert_eq!(
76            modifier.apply(&action_map, &time, true.into()),
77            Vec2::Y.into()
78        );
79        assert_eq!(
80            modifier.apply(&action_map, &time, false.into()),
81            Vec2::ZERO.into()
82        );
83        assert_eq!(
84            modifier.apply(&action_map, &time, 1.0.into()),
85            Vec2::Y.into()
86        );
87        assert_eq!(
88            modifier.apply(&action_map, &time, (0.0, 1.0).into()),
89            (1.0, 0.0).into()
90        );
91        assert_eq!(
92            modifier.apply(&action_map, &time, (0.0, 1.0, 2.0).into()),
93            (1.0, 0.0, 2.0).into(),
94        );
95    }
96
97    #[test]
98    fn zyx() {
99        let mut modifier = SwizzleAxis::ZYX;
100        let action_map = ActionMap::default();
101        let time = Time::default();
102
103        assert_eq!(
104            modifier.apply(&action_map, &time, true.into()),
105            Vec3::Z.into()
106        );
107        assert_eq!(
108            modifier.apply(&action_map, &time, false.into()),
109            Vec3::ZERO.into()
110        );
111        assert_eq!(
112            modifier.apply(&action_map, &time, 1.0.into()),
113            Vec3::Z.into()
114        );
115        assert_eq!(
116            modifier.apply(&action_map, &time, (0.0, 1.0).into()),
117            (0.0, 1.0).into()
118        );
119        assert_eq!(
120            modifier.apply(&action_map, &time, (0.0, 1.0, 2.0).into()),
121            (2.0, 1.0, 0.0).into(),
122        );
123    }
124
125    #[test]
126    fn xzy() {
127        let mut modifier = SwizzleAxis::XZY;
128        let action_map = ActionMap::default();
129        let time = Time::default();
130
131        assert_eq!(modifier.apply(&action_map, &time, true.into()), 1.0.into());
132        assert_eq!(modifier.apply(&action_map, &time, false.into()), 0.0.into());
133        assert_eq!(modifier.apply(&action_map, &time, 1.0.into()), 1.0.into());
134        assert_eq!(
135            modifier.apply(&action_map, &time, (0.0, 1.0).into()),
136            (0.0, 0.0).into()
137        );
138        assert_eq!(
139            modifier.apply(&action_map, &time, (0.0, 1.0, 2.0).into()),
140            (0.0, 2.0, 1.0).into(),
141        );
142    }
143
144    #[test]
145    fn yzx() {
146        let mut modifier = SwizzleAxis::YZX;
147        let action_map = ActionMap::default();
148        let time = Time::default();
149
150        assert_eq!(
151            modifier.apply(&action_map, &time, true.into()),
152            Vec3::Z.into()
153        );
154        assert_eq!(
155            modifier.apply(&action_map, &time, false.into()),
156            Vec3::ZERO.into()
157        );
158        assert_eq!(
159            modifier.apply(&action_map, &time, 1.0.into()),
160            Vec3::Z.into()
161        );
162        assert_eq!(
163            modifier.apply(&action_map, &time, (0.0, 1.0).into()),
164            (1.0, 0.0).into()
165        );
166        assert_eq!(
167            modifier.apply(&action_map, &time, (0.0, 1.0, 2.0).into()),
168            (1.0, 2.0, 0.0).into(),
169        );
170    }
171
172    #[test]
173    fn zxy() {
174        let mut modifier = SwizzleAxis::ZXY;
175        let action_map = ActionMap::default();
176        let time = Time::default();
177
178        assert_eq!(
179            modifier.apply(&action_map, &time, true.into()),
180            Vec2::Y.into()
181        );
182        assert_eq!(
183            modifier.apply(&action_map, &time, false.into()),
184            Vec2::ZERO.into()
185        );
186        assert_eq!(
187            modifier.apply(&action_map, &time, 1.0.into()),
188            Vec2::Y.into()
189        );
190        assert_eq!(
191            modifier.apply(&action_map, &time, (0.0, 1.0).into()),
192            (0.0, 0.0).into()
193        );
194        assert_eq!(
195            modifier.apply(&action_map, &time, (0.0, 1.0, 2.0).into()),
196            (2.0, 0.0, 1.0).into(),
197        );
198    }
199}