Skip to main content

goud_engine/core/input_manager/
actions.rs

1//! Action mapping methods for semantic input handling.
2
3use super::manager::InputManager;
4use super::types::InputBinding;
5
6impl InputManager {
7    // === Action Mapping ===
8
9    /// Maps an input binding to an action.
10    ///
11    /// An action can have multiple bindings. If the action already exists,
12    /// the binding is added to its list. Duplicate bindings are allowed.
13    ///
14    /// # Example
15    ///
16    /// ```ignore
17    /// use goud_engine::ecs::{InputManager, InputBinding};
18    /// use glfw::Key;
19    ///
20    /// let mut input = InputManager::new();
21    /// input.map_action("Jump", InputBinding::Key(Key::Space));
22    /// input.map_action("Jump", InputBinding::Key(Key::W)); // Alternative binding
23    /// ```
24    pub fn map_action(&mut self, action: impl Into<String>, binding: InputBinding) {
25        self.action_mappings
26            .entry(action.into())
27            .or_default()
28            .push(binding);
29    }
30
31    /// Unmaps a specific input binding from an action.
32    ///
33    /// Returns true if the binding was removed, false if it wasn't found.
34    pub fn unmap_action(&mut self, action: &str, binding: InputBinding) -> bool {
35        if let Some(bindings) = self.action_mappings.get_mut(action) {
36            if let Some(pos) = bindings.iter().position(|b| *b == binding) {
37                bindings.remove(pos);
38                return true;
39            }
40        }
41        false
42    }
43
44    /// Removes all bindings for an action.
45    ///
46    /// Returns true if the action existed and was removed.
47    pub fn clear_action(&mut self, action: &str) -> bool {
48        self.action_mappings.remove(action).is_some()
49    }
50
51    /// Removes all action mappings.
52    pub fn clear_all_actions(&mut self) {
53        self.action_mappings.clear();
54    }
55
56    /// Returns all bindings for an action.
57    ///
58    /// Returns an empty slice if the action doesn't exist.
59    pub fn get_action_bindings(&self, action: &str) -> &[InputBinding] {
60        self.action_mappings
61            .get(action)
62            .map(|v| v.as_slice())
63            .unwrap_or(&[])
64    }
65
66    /// Returns true if the action has any bindings.
67    pub fn has_action(&self, action: &str) -> bool {
68        self.action_mappings.contains_key(action)
69    }
70
71    /// Returns an iterator over all action names.
72    pub fn action_names(&self) -> impl Iterator<Item = &str> {
73        self.action_mappings.keys().map(|s| s.as_str())
74    }
75
76    /// Returns the number of registered actions.
77    pub fn action_count(&self) -> usize {
78        self.action_mappings.len()
79    }
80
81    /// Returns true if ANY binding for the action is currently pressed.
82    ///
83    /// Returns false if the action doesn't exist or has no bindings.
84    pub fn action_pressed(&self, action: &str) -> bool {
85        self.action_mappings
86            .get(action)
87            .is_some_and(|bindings| bindings.iter().any(|b| b.is_pressed(self)))
88    }
89
90    /// Returns true if ANY binding for the action was just pressed this frame.
91    ///
92    /// Returns false if the action doesn't exist or has no bindings.
93    pub fn action_just_pressed(&self, action: &str) -> bool {
94        self.action_mappings
95            .get(action)
96            .is_some_and(|bindings| bindings.iter().any(|b| b.is_just_pressed(self)))
97    }
98
99    /// Returns true if ANY binding for the action was just released this frame.
100    ///
101    /// Returns false if the action doesn't exist or has no bindings.
102    pub fn action_just_released(&self, action: &str) -> bool {
103        self.action_mappings
104            .get(action)
105            .is_some_and(|bindings| bindings.iter().any(|b| b.is_just_released(self)))
106    }
107
108    /// Returns the strength of the action (0.0-1.0).
109    ///
110    /// For digital inputs (keys, buttons), this returns 1.0 if pressed, 0.0 otherwise.
111    /// This method exists for future analog input support (triggers, analog sticks).
112    pub fn action_strength(&self, action: &str) -> f32 {
113        if self.action_pressed(action) {
114            1.0
115        } else {
116            0.0
117        }
118    }
119}