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}