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 proto;
11pub mod window;
12
13/// The state of a button, ether pressed or released.
14#[derive(HasSchema, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
15#[repr(u8)]
16pub enum ButtonState {
17    /// The button is pressed.
18    Pressed,
19    #[default]
20    /// The button is released.
21    Released,
22}
23
24impl ButtonState {
25    /// Get whether or not the button is pressed.
26    pub fn pressed(&self) -> bool {
27        matches!(self, ButtonState::Pressed)
28    }
29}
30
31/// Module prelude.
32pub mod prelude {
33    pub use super::{gamepad::*, keyboard::*, mouse::*, proto, window::*, ButtonState};
34    pub use crate::input::{
35        Controls, DenseControl, DenseInput, DenseInputCollector, DenseInputConfig, InputCollector,
36    };
37}
38
39/// Maps raw inputs to game controls and exposes controls for respective player and their control source.
40///
41/// [`InputCollector::apply_inputs`] maps raw input to game controls and updates them.
42///
43/// [`InputCollector::update_just_pressed`] computes any changes in pressed buttons that may be stored on control.
44///
45/// [`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.
46pub trait InputCollector<'a, Control>: Send + Sync {
47    /// Update the internal state with new inputs. This must be called every render frame with the
48    /// input events. This updates which buttons are pressed, but does not compute what buttons were "just_pressed".
49    /// use [`InputCollector::update_just_pressed`] to do this.
50    fn apply_inputs(&mut self, world: &World);
51
52    /// Indicate input for this frame has been consumed. An implementation of [`InputCollector`] that is
53    /// used with a fixed simulation step may track what keys are currently pressed, and what keys were "just pressed",
54    /// (changing from previous state).
55    ///
56    /// This saves current inputs as previous frame's inputs, allowing for determining what is "just pressed" next frame.
57    fn advance_frame(&mut self);
58
59    /// Update which buttons have been "just pressed", when input has changed from last frame and current input state.
60    ///
61    /// This does not modify previous frame's input, to do this use [`InputCollector::advance_frame`].
62    fn update_just_pressed(&mut self);
63
64    /// Get control for player.
65    fn get_control(&self) -> &Control;
66}
67
68/// Trait that tracks player control state. Provides associated types for other input trait implementations.
69pub trait Controls<'a, Control> {
70    /// Get control for player.
71    fn get_control(&self, player_idx: usize) -> &Control;
72
73    /// Get mutable control for player.
74    fn get_control_mut(&mut self, player_idx: usize) -> &mut Control;
75}
76
77use std::fmt::Debug;
78
79/// Dense input for network replication.
80pub trait DenseInput:
81    bytemuck::Pod + bytemuck::Zeroable + Copy + Clone + PartialEq + Eq + Send + Sync
82{
83}
84
85/// Automatic implementation for `DenseInput`.
86impl<T> DenseInput for T where
87    T: bytemuck::Pod + bytemuck::Zeroable + Copy + Clone + PartialEq + Eq + Send + Sync
88{
89}
90
91/// Define input types used by game for use in networking.
92///
93/// As long as types `Controls` and `InputCollector` implement traits [`Controls`] and [`InputCollector`],
94/// trait bounds [`DenseControl`] and [`DenseInputCollector`] are automatically implemented.
95#[allow(missing_docs)]
96pub trait DenseInputConfig<'a> {
97    type Dense: DenseInput + Debug + Default;
98    type Control: DenseControl<Self::Dense>;
99
100    // Must be HasSchema because expected to be retrieved from `World` as `Resource`.
101    type Controls: Controls<'a, Self::Control> + HasSchema;
102
103    // InputCollector type params must match that of Controls, so using associated types.
104    type InputCollector: InputCollector<'a, Self::Control> + Default;
105}
106
107///  Trait allowing for creating and applying [`DenseInput`] from control.
108pub trait DenseControl<Dense: DenseInput>: Send + Sync + Default {
109    /// Get [`DenseInput`] for control.
110    fn get_dense_input(&self) -> Dense;
111
112    /// Update control from [`DenseInput`].
113    fn update_from_dense(&mut self, new_control: &Dense);
114}
115
116/// Extension of [`InputCollector`] exposing dense control for networking.
117///
118/// This trait is automatically implemented for [`InputCollector`]'s such that `Control`
119/// implements [`DenseControl`] (i.e. implements dense input)
120pub trait DenseInputCollector<'a, Dense, Control>: InputCollector<'a, Control>
121where
122    Dense: DenseInput,
123    Control: DenseControl<Dense>,
124{
125    /// Get dense control
126    fn get_dense_control(&self) -> Dense;
127}
128
129/// Provide automatic [`DenseInputCollector`] for [`InputCollector`] when type parameters
130/// meet required bounds for networking.
131impl<'a, T, Dense, Control> DenseInputCollector<'a, Dense, Control> for T
132where
133    Dense: DenseInput,
134    Control: DenseControl<Dense>,
135    T: InputCollector<'a, Control>,
136{
137    fn get_dense_control(&self) -> Dense {
138        self.get_control().get_dense_input()
139    }
140}