bones_framework/input.rs
1//! Input resources.
2
3use bones_lib::ecs::World;
4use bones_schema::HasSchema;
5
6pub mod gamepad;
7pub mod gilrs;
8pub mod keyboard;
9pub mod mouse;
10pub mod window;
11
12/// The state of a button, ether pressed or released.
13#[derive(HasSchema, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
14#[repr(u8)]
15pub enum ButtonState {
16 /// The button is pressed.
17 Pressed,
18 #[default]
19 /// The button is released.
20 Released,
21}
22
23impl ButtonState {
24 /// Get whether or not the button is pressed.
25 pub fn pressed(&self) -> bool {
26 matches!(self, ButtonState::Pressed)
27 }
28}
29
30/// Module prelude.
31pub mod prelude {
32 pub use super::{gamepad::*, keyboard::*, mouse::*, window::*, ButtonState};
33 pub use crate::input::{InputCollector, PlayerControls};
34}
35
36/// Maps raw inputs to game controls and exposes controls for respective player and their control source.
37///
38/// [`InputCollector::apply_inputs`] maps raw input to game controls and updates them.
39///
40/// [`InputCollector::update_just_pressed`] computes any changes in pressed buttons that may be stored on control.
41///
42/// [`InputCollector::advance_frame`] is used to mark that the input has been consumed, and update the prev frame inputs to current, to compute changes next frame.
43///
44/// Generic type param ControlMapping is HasSchema because it is expected to be a Resource retrievable on world.
45pub trait InputCollector<'a, ControlMapping: HasSchema, ControlSource, Control>:
46 Send + Sync
47{
48 /// Update the internal state with new inputs. This must be called every render frame with the
49 /// input events. This updates which buttons are pressed, but does not compute what buttons were "just_pressed".
50 /// use [`InputCollector::update_just_pressed`] to do this.
51 fn apply_inputs(&mut self, world: &World);
52
53 /// Indicate input for this frame has been consumed. An implementation of [`InputCollector`] that is
54 /// used with a fixed simulation step may track what keys are currently pressed, and what keys were "just pressed",
55 /// (changing from previous state).
56 ///
57 /// This saves current inputs as previous frame's inputs, allowing for determining what is "just pressed" next frame.
58 fn advance_frame(&mut self);
59
60 /// Update which buttons have been "just pressed", when input has changed from last frame and current input state.
61 ///
62 /// This does not modify previous frame's input, to do this use [`InputCollector::advance_frame`].
63 fn update_just_pressed(&mut self);
64
65 /// Get control for player based on provided `ControlSource`.
66 fn get_control(&self, player_idx: usize, control_source: ControlSource) -> &Control;
67}
68
69/// Trait that tracks player control state. Provides associated types for other input trait implementations.
70pub trait PlayerControls<'a, Control> {
71 /// InputCollector used to update controls.
72 type InputCollector: InputCollector<'a, Self::ControlMapping, Self::ControlSource, Control>;
73
74 /// Control mapping from raw input, expected to be able to be retrieved as `Resource` from world.
75 type ControlMapping: HasSchema;
76
77 /// Type used to map source of input to control.
78 type ControlSource;
79
80 /// Update control state from input collector.
81 fn update_controls(&mut self, collector: &mut Self::InputCollector);
82
83 /// Get `ControlSource` for player (only present for local player).
84 fn get_control_source(&self, local_player_idx: usize) -> Option<Self::ControlSource>;
85
86 /// Get control for player.
87 fn get_control(&self, player_idx: usize) -> &Control;
88
89 /// Get mutable control for player.
90 fn get_control_mut(&mut self, player_idx: usize) -> &mut Control;
91}