leafwing_input_manager/action_state/
action_data.rs

1//! Contains types used to store the state of the actions held in an [`ActionState`](super::ActionState).
2
3use bevy::{
4    math::{Vec2, Vec3},
5    platform::time::Instant,
6    reflect::Reflect,
7};
8use serde::{Deserialize, Serialize};
9
10use crate::buttonlike::ButtonValue;
11#[cfg(feature = "timing")]
12use crate::timing::Timing;
13use crate::{InputControlKind, buttonlike::ButtonState};
14
15/// Data about the state of an action.
16///
17/// Universal data about the state of the data is stored directly in this struct,
18/// while data for each kind of action (buttonlike, axislike...) is stored in the `kind_data` field.
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
20pub struct ActionData {
21    /// Whether or not the action is disabled.
22    ///
23    /// While disabled, buttons will always report as released, and axes will always report as 0.
24    pub disabled: bool,
25    /// The data for the action.
26    pub kind_data: ActionKindData,
27}
28
29impl ActionData {
30    /// Constructs a new `ActionData` with default values corresponding to the given `kind_data`.
31    pub fn from_kind(input_control_kind: InputControlKind) -> Self {
32        Self {
33            disabled: false,
34            kind_data: match input_control_kind {
35                InputControlKind::Button => ActionKindData::Button(ButtonData::default()),
36                InputControlKind::Axis => ActionKindData::Axis(AxisData::default()),
37                InputControlKind::DualAxis => ActionKindData::DualAxis(DualAxisData::default()),
38                InputControlKind::TripleAxis => {
39                    ActionKindData::TripleAxis(TripleAxisData::default())
40                }
41            },
42        }
43    }
44
45    /// Ticks the action data, updating the state of the action.
46    pub fn tick(&mut self, _current_instant: Instant, _previous_instant: Instant) {
47        match self.kind_data {
48            ActionKindData::Button(ref mut data) => {
49                data.state.tick();
50
51                #[cfg(feature = "timing")]
52                data.timing.tick(_current_instant, _previous_instant);
53            }
54            ActionKindData::Axis(ref mut _data) => {}
55            ActionKindData::DualAxis(ref mut _data) => {}
56            ActionKindData::TripleAxis(ref mut _data) => {}
57        }
58    }
59}
60
61/// A wrapper over the various forms of data that an action can take.
62#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
63pub enum ActionKindData {
64    /// The data for a button-like action.
65    Button(ButtonData),
66    /// The data for an axis-like action.
67    Axis(AxisData),
68    /// The data for a dual-axis-like action.
69    DualAxis(DualAxisData),
70    /// The data for a triple-axis-like action.
71    TripleAxis(TripleAxisData),
72}
73
74impl ActionKindData {
75    pub(super) fn swap_to_update_state(&mut self) {
76        // save the changes applied to `state` into `fixed_update_state`
77        // switch to loading the `update_state` into `state`
78        match self {
79            Self::Button(data) => {
80                data.fixed_update_state = data.state;
81                data.fixed_update_value = data.value;
82                data.state = data.update_state;
83                data.value = data.update_value;
84            }
85            Self::Axis(data) => {
86                data.fixed_update_value = data.value;
87                data.value = data.update_value;
88            }
89            Self::DualAxis(data) => {
90                data.fixed_update_pair = data.pair;
91                data.pair = data.update_pair;
92            }
93            Self::TripleAxis(data) => {
94                data.fixed_update_triple = data.triple;
95                data.triple = data.update_triple;
96            }
97        }
98    }
99
100    pub(super) fn swap_to_fixed_update_state(&mut self) {
101        // save the changes applied to `state` into `update_state`
102        // switch to loading the `fixed_update_state` into `state`
103        match self {
104            Self::Button(data) => {
105                data.update_state = data.state;
106                data.update_value = data.value;
107                data.state = data.fixed_update_state;
108                data.value = data.fixed_update_value;
109            }
110            Self::Axis(data) => {
111                data.update_value = data.value;
112                data.value = data.fixed_update_value;
113            }
114            Self::DualAxis(data) => {
115                data.update_pair = data.pair;
116                data.pair = data.fixed_update_pair;
117            }
118            Self::TripleAxis(data) => {
119                data.update_triple = data.triple;
120                data.triple = data.fixed_update_triple;
121            }
122        }
123    }
124
125    // set the `update_state` to the current `state`
126    pub(super) fn set_update_state_from_state(&mut self) {
127        match self {
128            Self::Button(data) => {
129                data.update_state = data.state;
130                data.update_value = data.value;
131            }
132            Self::Axis(data) => {
133                data.update_value = data.value;
134            }
135            Self::DualAxis(data) => {
136                data.update_pair = data.pair;
137            }
138            Self::TripleAxis(data) => {
139                data.update_triple = data.triple;
140            }
141        }
142    }
143
144    // set the `fixed_update_state` to the current `state`
145    pub(super) fn set_fixed_update_state_from_state(&mut self) {
146        match self {
147            Self::Button(data) => {
148                data.fixed_update_state = data.state;
149                data.fixed_update_value = data.value;
150            }
151            Self::Axis(data) => {
152                data.fixed_update_value = data.value;
153            }
154            Self::DualAxis(data) => {
155                data.fixed_update_pair = data.pair;
156            }
157            Self::TripleAxis(data) => {
158                data.fixed_update_triple = data.triple;
159            }
160        }
161    }
162}
163
164/// Metadata about an [`Buttonlike`](crate::user_input::Buttonlike) action
165#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Reflect)]
166pub struct ButtonData {
167    /// Is the action pressed or released?
168    pub state: ButtonState,
169    /// The `state` of the action in the `Main` schedule
170    pub update_state: ButtonState,
171    /// The `state` of the action in the `FixedMain` schedule
172    pub fixed_update_state: ButtonState,
173    /// How far has the button been pressed
174    pub value: f32,
175    /// The `value` of the action in the `Main` schedule
176    pub update_value: f32,
177    /// The `value` of the action in the `FixedMain` schedule
178    pub fixed_update_value: f32,
179    /// When was the button pressed / released, and how long has it been held for?
180    #[cfg(feature = "timing")]
181    pub timing: Timing,
182}
183
184impl ButtonData {
185    /// The default data for a button that was just pressed.
186    pub const JUST_PRESSED: Self = Self {
187        state: ButtonState::JustPressed,
188        update_state: ButtonState::JustPressed,
189        fixed_update_state: ButtonState::JustPressed,
190        value: 1.0,
191        update_value: 1.0,
192        fixed_update_value: 1.0,
193        #[cfg(feature = "timing")]
194        timing: Timing::NEW,
195    };
196
197    /// The default data for a button that was just released.
198    pub const JUST_RELEASED: Self = Self {
199        state: ButtonState::JustReleased,
200        update_state: ButtonState::JustReleased,
201        fixed_update_state: ButtonState::JustReleased,
202        value: 0.0,
203        update_value: 0.0,
204        fixed_update_value: 0.0,
205        #[cfg(feature = "timing")]
206        timing: Timing::NEW,
207    };
208
209    /// The default data for a button that is released,
210    /// but was not just released.
211    ///
212    /// This is the default state for a button,
213    /// as it avoids surprising behavior when the button is first created.
214    pub const RELEASED: Self = Self {
215        state: ButtonState::Released,
216        update_state: ButtonState::Released,
217        fixed_update_state: ButtonState::Released,
218        value: 0.0,
219        update_value: 0.0,
220        fixed_update_value: 0.0,
221        #[cfg(feature = "timing")]
222        timing: Timing::NEW,
223    };
224
225    /// Is the action currently pressed?
226    #[inline]
227    #[must_use]
228    pub fn pressed(&self) -> bool {
229        self.state.pressed()
230    }
231
232    /// Was the action pressed since the last time it was ticked?
233    #[inline]
234    #[must_use]
235    pub fn just_pressed(&self) -> bool {
236        self.state.just_pressed()
237    }
238
239    /// Is the action currently released?
240    #[inline]
241    #[must_use]
242    pub fn released(&self) -> bool {
243        self.state.released()
244    }
245
246    /// Was the action released since the last time it was ticked?
247    #[inline]
248    #[must_use]
249    pub fn just_released(&self) -> bool {
250        self.state.just_released()
251    }
252
253    /// Convert `self` to a [`ButtonValue`].
254    #[inline]
255    #[must_use]
256    pub fn to_button_value(&self) -> ButtonValue {
257        ButtonValue::new(self.state.pressed(), self.value)
258    }
259}
260
261/// The raw data for an [`ActionState`](super::ActionState) corresponding to a single virtual axis.
262#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, Reflect)]
263pub struct AxisData {
264    /// How far the axis is currently pressed
265    pub value: f32,
266    /// The `value` of the action in the `Main` schedule
267    pub update_value: f32,
268    /// The `value` of the action in the `FixedMain` schedule
269    pub fixed_update_value: f32,
270}
271
272/// The raw data for an [`ActionState`](super::ActionState) corresponding to a pair of virtual axes.
273#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, Reflect)]
274pub struct DualAxisData {
275    /// The XY coordinates of the axis
276    pub pair: Vec2,
277    /// The `pair` of the action in the `Main` schedule
278    pub update_pair: Vec2,
279    /// The `pair` of the action in the `FixedMain` schedule
280    pub fixed_update_pair: Vec2,
281}
282
283/// The raw data for an [`ActionState`](super::ActionState) corresponding to a triple of virtual axes.
284#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, Reflect)]
285pub struct TripleAxisData {
286    /// The XYZ coordinates of the axis
287    pub triple: Vec3,
288    /// The `triple` of the action in the `Main` schedule
289    pub update_triple: Vec3,
290    /// The `triple` of the action in the `FixedMain` schedule
291    pub fixed_update_triple: Vec3,
292}
293
294#[cfg(test)]
295mod tests {
296    use crate::buttonlike::ButtonState;
297
298    #[test]
299    fn test_tick_triple_axis() {
300        use super::ActionData;
301        use super::ActionKindData;
302        use super::TripleAxisData;
303        use bevy::platform::time::Instant;
304
305        let mut action_data = ActionData {
306            disabled: false,
307            kind_data: ActionKindData::TripleAxis(TripleAxisData {
308                triple: bevy::math::Vec3::new(1.0, 2.0, 3.0),
309                update_triple: bevy::math::Vec3::new(4.0, 5.0, 6.0),
310                fixed_update_triple: bevy::math::Vec3::new(7.0, 8.0, 9.0),
311            }),
312        };
313
314        let previous_instant = Instant::now();
315        let current_instant = previous_instant + std::time::Duration::from_secs(1);
316
317        action_data.tick(current_instant, previous_instant);
318
319        if let ActionKindData::TripleAxis(data) = &action_data.kind_data {
320            assert_eq!(data.triple, bevy::math::Vec3::new(1.0, 2.0, 3.0));
321        } else {
322            panic!("Expected TripleAxisData");
323        }
324    }
325
326    #[test]
327    fn test_swap_update_to_update_state_triple_axis() {
328        use super::ActionData;
329        use super::ActionKindData;
330        use super::TripleAxisData;
331        use bevy::math::Vec3;
332
333        let mut action_data = ActionData {
334            disabled: false,
335            kind_data: ActionKindData::TripleAxis(TripleAxisData {
336                triple: Vec3::new(1.0, 2.0, 3.0),
337                update_triple: Vec3::new(4.0, 5.0, 6.0),
338                fixed_update_triple: Vec3::new(7.0, 8.0, 9.0),
339            }),
340        };
341
342        action_data.kind_data.swap_to_update_state();
343
344        if let ActionKindData::TripleAxis(data) = &action_data.kind_data {
345            assert_eq!(data.triple, Vec3::new(4.0, 5.0, 6.0));
346        } else {
347            panic!("Expected TripleAxisData");
348        }
349    }
350
351    #[test]
352    fn test_swap_to_fixed_update_state_triple_axis() {
353        use super::ActionData;
354        use super::ActionKindData;
355        use super::TripleAxisData;
356        use bevy::math::Vec3;
357
358        let mut action_data = ActionData {
359            disabled: false,
360            kind_data: ActionKindData::TripleAxis(TripleAxisData {
361                triple: Vec3::new(1.0, 2.0, 3.0),
362                update_triple: Vec3::new(4.0, 5.0, 6.0),
363                fixed_update_triple: Vec3::new(7.0, 8.0, 9.0),
364            }),
365        };
366
367        action_data.kind_data.swap_to_fixed_update_state();
368
369        if let ActionKindData::TripleAxis(data) = &action_data.kind_data {
370            assert_eq!(data.triple, Vec3::new(7.0, 8.0, 9.0));
371        } else {
372            panic!("Expected TripleAxisData");
373        }
374    }
375
376    #[test]
377    fn test_set_update_state_from_state_axis() {
378        use super::ActionData;
379        use super::ActionKindData;
380        use super::AxisData;
381
382        let mut action_data = ActionData {
383            disabled: false,
384            kind_data: ActionKindData::Axis(AxisData {
385                value: 1.0,
386                update_value: 2.0,
387                fixed_update_value: 3.0,
388            }),
389        };
390
391        action_data.kind_data.set_update_state_from_state();
392
393        if let ActionKindData::Axis(data) = &action_data.kind_data {
394            assert_eq!(data.update_value, 1.0);
395        } else {
396            panic!("Expected AxisData");
397        }
398    }
399
400    #[test]
401    fn test_set_update_state_from_state_dual_axis() {
402        use super::ActionData;
403        use super::ActionKindData;
404        use super::DualAxisData;
405        use bevy::math::Vec2;
406
407        let mut action_data = ActionData {
408            disabled: false,
409            kind_data: ActionKindData::DualAxis(DualAxisData {
410                pair: Vec2::new(1.0, 2.0),
411                update_pair: Vec2::new(3.0, 4.0),
412                fixed_update_pair: Vec2::new(5.0, 6.0),
413            }),
414        };
415
416        action_data.kind_data.set_update_state_from_state();
417
418        if let ActionKindData::DualAxis(data) = &action_data.kind_data {
419            assert_eq!(data.update_pair, Vec2::new(1.0, 2.0));
420        } else {
421            panic!("Expected DualAxisData");
422        }
423    }
424
425    #[test]
426    fn test_set_update_state_from_state_triple_axis() {
427        use super::ActionData;
428        use super::ActionKindData;
429        use super::TripleAxisData;
430        use bevy::math::Vec3;
431
432        let mut action_data = ActionData {
433            disabled: false,
434            kind_data: ActionKindData::TripleAxis(TripleAxisData {
435                triple: Vec3::new(1.0, 2.0, 3.0),
436                update_triple: Vec3::new(4.0, 5.0, 6.0),
437                fixed_update_triple: Vec3::new(7.0, 8.0, 9.0),
438            }),
439        };
440
441        action_data.kind_data.set_update_state_from_state();
442
443        if let ActionKindData::TripleAxis(data) = &action_data.kind_data {
444            assert_eq!(data.update_triple, Vec3::new(1.0, 2.0, 3.0));
445        } else {
446            panic!("Expected TripleAxisData");
447        }
448    }
449
450    #[test]
451    fn test_set_fixed_update_state_from_state_button() {
452        use super::ActionData;
453        use super::ActionKindData;
454        use super::ButtonData;
455
456        let mut action_data = ActionData {
457            disabled: false,
458            kind_data: ActionKindData::Button(ButtonData {
459                state: ButtonState::Pressed,
460                update_state: ButtonState::JustPressed,
461                fixed_update_state: ButtonState::Released,
462                value: 1.0,
463                update_value: 0.5,
464                fixed_update_value: 0.0,
465                #[cfg(feature = "timing")]
466                timing: Default::default(),
467            }),
468        };
469
470        action_data.kind_data.set_fixed_update_state_from_state();
471        if let ActionKindData::Button(data) = &action_data.kind_data {
472            assert_eq!(data.fixed_update_state, ButtonState::Pressed);
473            assert_eq!(data.fixed_update_value, 1.0);
474        } else {
475            panic!("Expected ButtonData");
476        }
477    }
478
479    #[test]
480    fn test_set_fixed_update_state_from_state_axis() {
481        use super::ActionData;
482        use super::ActionKindData;
483        use super::AxisData;
484
485        let mut action_data = ActionData {
486            disabled: false,
487            kind_data: ActionKindData::Axis(AxisData {
488                value: 1.0,
489                update_value: 2.0,
490                fixed_update_value: 3.0,
491            }),
492        };
493
494        action_data.kind_data.set_fixed_update_state_from_state();
495
496        if let ActionKindData::Axis(data) = &action_data.kind_data {
497            assert_eq!(data.fixed_update_value, 1.0);
498        } else {
499            panic!("Expected AxisData");
500        }
501    }
502
503    #[test]
504    fn test_set_fixed_update_state_from_state_dual_axis() {
505        use super::ActionData;
506        use super::ActionKindData;
507        use super::DualAxisData;
508        use bevy::math::Vec2;
509
510        let mut action_data = ActionData {
511            disabled: false,
512            kind_data: ActionKindData::DualAxis(DualAxisData {
513                pair: Vec2::new(1.0, 2.0),
514                update_pair: Vec2::new(3.0, 4.0),
515                fixed_update_pair: Vec2::new(5.0, 6.0),
516            }),
517        };
518
519        action_data.kind_data.set_fixed_update_state_from_state();
520
521        if let ActionKindData::DualAxis(data) = &action_data.kind_data {
522            assert_eq!(data.fixed_update_pair, Vec2::new(1.0, 2.0));
523        } else {
524            panic!("Expected DualAxisData");
525        }
526    }
527
528    #[test]
529    fn test_set_fixed_update_state_from_state_triple_axis() {
530        use super::ActionData;
531        use super::ActionKindData;
532        use super::TripleAxisData;
533        use bevy::math::Vec3;
534
535        let mut action_data = ActionData {
536            disabled: false,
537            kind_data: ActionKindData::TripleAxis(TripleAxisData {
538                triple: Vec3::new(1.0, 2.0, 3.0),
539                update_triple: Vec3::new(4.0, 5.0, 6.0),
540                fixed_update_triple: Vec3::new(7.0, 8.0, 9.0),
541            }),
542        };
543
544        action_data.kind_data.set_fixed_update_state_from_state();
545
546        if let ActionKindData::TripleAxis(data) = &action_data.kind_data {
547            assert_eq!(data.fixed_update_triple, Vec3::new(1.0, 2.0, 3.0));
548        } else {
549            panic!("Expected TripleAxisData");
550        }
551    }
552}