cogs_gamedev/controls/mod.rs
1//! Query the player's input and turn it into controls.
2//!
3//! This module defines two main structs: `PollingInputHandler` and `EventInputHandler`.
4//!
5//! `PollingInputHandler` is used when your game engine provides player input by polling for it. The GGEZ library
6//! uses this method; you can call `keyboard::get_keyboard_input` and get what keys are pressed that way.
7//!
8//! `EventInputHandler` is used when your game engine provides player input by producing Input events. SDL2 and
9//! browsers with WASM work this way. I believe Piston also works this way, but I've never worked with Piston.
10//!
11//! # API
12//!
13//! Both styles of input handling implement the same trait, `InputHandler`. It has functions for querying the state of the
14//! controls, but not for updating them.
15//! This lets you write your main loop function generic over the kind of input handler you have, in case you want
16//! to port your game to platforms with different input styles.
17//!
18//! # Updating the Inputs
19//!
20//! It is VERY IMPORTANT that before you do *any* processing in your main loop you call `InputHandler::update`.
21//! This tells the input handler that the next frame has elapsed.
22//!
23//! For `PollingInputHandler`, you must pass in a `&HashSet` containing all the pressed keys to `update`.
24//!
25//! `EventInputHandler` also exposes `input_down` and `input_up`, which you must call upon getting an input event.
26//!
27//! # Generics
28//!
29//! To work with all the ways game libraries deal with input handling, the Input Handlers are generic over
30//! the inputs `I` that the game engine gives you, and the controls `C` that your game uses.
31//!
32//! Inputs must be hashable (so, `Hash + Eq + PartialEq`).
33//!
34//! Controls must be useable with the EnumMap crate. You can do that easily enough with `#[derive(Enum)]`. (Internally,
35//! the handlers use EnumMap to map each control to how long it has been held down.).
36//!
37//! Both of them must impl Clone (or Copy).
38//!
39//! It will probably be useful to define some type aliases to prevent having to type out your generics over and over
40//! again. For example:
41//!
42// we ignore this block of code because i really don't want to bother with importing
43// all those game libraries...
44//! ```ignore
45//! ##[derive(Enum)]
46//! enum MyControls {
47//! Up,
48//! Down,
49//! Left,
50//! Right,
51//! Jump,
52//! Pause,
53//! }
54//!
55//! /// When you're writing a game with GGEZ
56//! mod ggez_game {
57//! type InputHandler = PollingInputHandler<ggez::input::keyboard::KeyCode, super::MyControls>;
58//! }
59//!
60//! /// When you're writing a game with Piston
61//! mod piston_game {
62//! type InputHandler = EventInputHandler<piston::input::keyboard::Key, super::MyControls>;
63//! }
64//!
65//! /// When you're writing a game for the browser with wasm-pack or similar
66//! mod browser_wasm_js_something {
67//! type InputHandler = EventInputHandler<String, super::MyControls>;
68//! }
69//!
70//! ```
71//!
72//! # Changing Controls on the Fly
73//!
74//! Both input handlers support changing controls on the fly (perhaps through some sort of menu).
75//! Call `listen_for_control_change` with the control you want to update the input for, and the next time an input
76//! is received, that control will be associated with that input.
77//!
78//! If multiple controls are pressed at the same time during a frame where the input handler is
79//! listening for a control change, it's undefined which one the control will be set to.
80//! It will be set to one of them, however.
81
82mod polling;
83pub use polling::PollingInputHandler;
84mod event;
85pub use event::EventInputHandler;
86
87use std::hash::Hash;
88
89use enum_map::Enum;
90
91/// The InputHandler trait, makng sure that both styles of input handling
92/// expose the same API.
93pub trait InputHandler<I: Hash + Eq + PartialEq + Clone, C: Enum<u32> + Clone> {
94 /// Is this input pressed down?
95 /// i.e. is the player pressing the button?
96 fn pressed(&self, control: C) -> bool;
97
98 /// Is this input released?
99 /// i.e. is the player *not* pressing the button?
100 fn released(&self, control: C) -> bool;
101
102 /// Is this input being clicked down?
103 /// i.e. was it up last frame, but down this frame?
104 fn clicked_down(&self, control: C) -> bool;
105}