mirage_engine/input/action.rs
1//! The action vocabularies a game reads its input through, and the three
2//! kinds they split into.
3
4use core::fmt;
5
6use crate::Seats;
7use crate::input::binding::{Axis2Binding, AxisBinding, ButtonBinding, Key};
8use crate::input::table::sealed::Binding as Persisted;
9
10/// Trait every action vocabulary implements, written by
11/// [`InputButtonAction`](crate::InputButtonAction),
12/// [`InputAxisAction`](crate::InputAxisAction) and
13/// [`InputAxis2Action`](crate::InputAxis2Action).
14///
15/// Required if you want to rebind or read an action generically; the kind
16/// traits are what a game implements by hand.
17pub trait InputAction: Copy + 'static {
18 /// Binding type for an action of this kind, which is what makes a
19 /// mis-kinded [`rebind`](crate::FrameContext::rebind) fail to compile.
20 type Binding: Persisted + fmt::Display;
21
22 /// Default controls this action is bound to, before a player changes
23 /// anything.
24 fn defaults(&self) -> Vec<Self::Binding>;
25
26 /// Every action of this vocabulary, which startup materializes into the
27 /// table a player rebinds; one this leaves out reads through nothing.
28 fn all() -> Vec<Self>;
29
30 /// Name this action is known by in code; also the name the store
31 /// keeps a rebind under.
32 fn name(&self) -> &'static str;
33
34 /// The action of this name, or `None` where the vocabulary has none.
35 fn from_name(name: &str) -> Option<Self>;
36}
37
38/// An action that reads back `true` while it is held.
39///
40/// Required if you want a verb with two states: a jump, a shot, a pause.
41pub trait InputButtonAction: InputAction<Binding = ButtonBinding> {
42 /// The controls this action starts out bound to; they are
43 /// alternatives, and any one of them holds it down.
44 fn bindings(&self) -> Vec<ButtonBinding>;
45}
46
47/// An action that reads back a number in `-1..=1`, or, bound to a
48/// [`PointerDelta`](crate::PointerDelta) or
49/// [`WheelDelta`](crate::WheelDelta) lane, how far it moved.
50///
51/// Required if you want a verb with a strength and a direction: a throttle,
52/// a lean, a turn.
53pub trait InputAxisAction: InputAction<Binding = AxisBinding> {
54 /// The controls this action starts out bound to; the one pushed
55 /// furthest is the one it reads.
56 fn bindings(&self) -> Vec<AxisBinding>;
57}
58
59/// An action that reads back a vector no longer than `1`, or, bound to
60/// [`Axis2Binding::pointer`](crate::Axis2Binding::pointer), how far the
61/// pointer moved.
62///
63/// Required if you want a verb with a direction in the plane: a walk, a
64/// look, a cursor.
65pub trait InputAxis2Action: InputAction<Binding = Axis2Binding> {
66 /// The controls this action starts out bound to; the one pushed
67 /// furthest is the one it reads.
68 fn bindings(&self) -> Vec<Axis2Binding>;
69}
70
71/// The three vocabularies one game plays with, named together as
72/// [`Game::InputActions`](crate::Game::InputActions).
73///
74/// Fill a kind a game has no verbs of with [`NoInputButtons`],
75/// [`NoInputAxes`] or [`NoInputAxes2`].
76pub trait InputActions {
77 /// The vocabulary whose actions read back as held or not.
78 type Button: InputButtonAction;
79 /// The vocabulary whose actions read back a number.
80 type Axis: InputAxisAction;
81 /// The vocabulary whose actions read back a vector.
82 type Axis2: InputAxis2Action;
83}
84
85impl<S: InputActions> Seats<S::Button, ButtonBinding> for S {}
86impl<S: InputActions> Seats<S::Axis, AxisBinding> for S {}
87impl<S: InputActions> Seats<S::Axis2, Axis2Binding> for S {}
88
89/// The input action set of a game that reads no input at all.
90///
91/// No value of it exists, so such a game reads no action.
92#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
93pub enum NoInputActions {}
94
95impl InputActions for NoInputActions {
96 type Button = NoInputButtons;
97 type Axis = NoInputAxes;
98 type Axis2 = NoInputAxes2;
99}
100
101/// The empty vocabulary of one kind: no value of it exists, so a game with
102/// no verb of that kind reads none.
103macro_rules! empty {
104 ($name:ident, $kind:ident, $binding:ident, $noun:literal) => {
105 #[doc = concat!("The vocabulary of a game with no ", $noun, " actions of its own.")]
106 ///
107 /// No value of it exists, so it fills the empty slot and nothing
108 /// else.
109 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
110 pub enum $name {}
111
112 impl InputAction for $name {
113 type Binding = $binding;
114
115 fn defaults(&self) -> Vec<$binding> {
116 match *self {}
117 }
118
119 fn all() -> Vec<Self> {
120 Vec::new()
121 }
122
123 fn name(&self) -> &'static str {
124 match *self {}
125 }
126
127 fn from_name(_name: &str) -> Option<Self> {
128 None
129 }
130 }
131
132 impl $kind for $name {
133 fn bindings(&self) -> Vec<$binding> {
134 match *self {}
135 }
136 }
137 };
138}
139
140empty!(NoInputButtons, InputButtonAction, ButtonBinding, "button");
141empty!(NoInputAxes, InputAxisAction, AxisBinding, "number");
142empty!(NoInputAxes2, InputAxis2Action, Axis2Binding, "vector");
143
144impl InputAction for Key {
145 type Binding = ButtonBinding;
146
147 fn defaults(&self) -> Vec<ButtonBinding> {
148 <Self as InputButtonAction>::bindings(self)
149 }
150
151 fn all() -> Vec<Self> {
152 Self::ALL.to_vec()
153 }
154
155 fn name(&self) -> &'static str {
156 self.token()
157 }
158
159 fn from_name(name: &str) -> Option<Self> {
160 Self::from_token(name)
161 }
162}
163
164/// A key is its own action, bound to itself: the vocabulary a prototype
165/// reads through before it has declared what the player does.
166impl InputButtonAction for Key {
167 fn bindings(&self) -> Vec<ButtonBinding> {
168 vec![ButtonBinding::Key(*self)]
169 }
170}
171
172impl InputActions for Key {
173 type Button = Key;
174 type Axis = NoInputAxes;
175 type Axis2 = NoInputAxes2;
176}