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}