From dfa70f43358ac927896197287aebd8594e21c45f Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 21:20:59 +0100 Subject: [PATCH] Add a bunch of docs for input --- agb/src/input.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/agb/src/input.rs b/agb/src/input.rs index c36866e4..8cc5fc87 100644 --- a/agb/src/input.rs +++ b/agb/src/input.rs @@ -2,10 +2,30 @@ use crate::fixnum::Vector2D; use bitflags::bitflags; use core::convert::From; +/// Tri-state enum. Allows for -1, 0 and +1. +/// Useful if checking if the D-Pad is pointing left, right, or unpressed. +/// +/// Note that [Tri] can be converted directly to a signed integer, so can easily be used to update positions of things in games +/// +/// # Examples +/// ```rust,no_run +/// # #![no_std] +/// use agb::input::Tri; +/// +/// # fn main() { +/// let x = 5; +/// let tri = Tri::Positive; // e.g. from button_controller.x_tri() +/// +/// assert_eq!(x + tri as i32, 6); +/// # } +/// ``` #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Tri { + /// Right or down Positive = 1, + /// Unpressed Zero = 0, + /// Left or up Negative = -1, } @@ -18,16 +38,27 @@ impl From<(bool, bool)> for Tri { } bitflags! { + /// Represents a button on the GBA pub struct Button: u32 { + /// The A button const A = 1 << 0; + /// The B button const B = 1 << 1; + /// The SELECT button const SELECT = 1 << 2; + /// The START button const START = 1 << 3; + /// The RIGHT button on the D-Pad const RIGHT = 1 << 4; + /// The LFET button on the D-Pad const LEFT = 1 << 5; + /// The UP button on the D-Pad const UP = 1 << 6; + /// The DOWN button on the D-Pad const DOWN = 1 << 7; + /// The R button on the D-Pad const R = 1 << 8; + /// The L button on the D-Pad const L = 1 << 9; } } @@ -36,6 +67,28 @@ const BUTTON_INPUT: *mut u16 = (0x04000130) as *mut u16; // const BUTTON_INTURRUPT: *mut u16 = (0x04000132) as *mut u16; +/// Helper to make it easy to get the current state of the GBA's buttons. +/// +/// # Example +/// +/// ```rust,no_run +/// # #![no_std] +/// use agb::input::{ButtonController, Tri}; +/// +/// # fn main() { +/// let mut input = ButtonController::new(); +/// +/// loop { +/// input.update(); // call update every loop +/// +/// match input.x_tri() { +/// Tri::Negative => { /* left is being pressed */ } +/// Tri::Positive => { /* right is being pressed */ } +/// Tri::Zero => { /* Neither left nor right (or both) are pressed */ } +/// } +/// } +/// # } +/// ``` pub struct ButtonController { previous: u16, current: u16, @@ -48,6 +101,8 @@ impl Default for ButtonController { } impl ButtonController { + /// Create a new ButtonController. + /// This is the preferred way to create it. #[must_use] pub fn new() -> Self { let pressed = !unsafe { BUTTON_INPUT.read_volatile() }; @@ -57,11 +112,16 @@ impl ButtonController { } } + /// Updates the state of the button controller. + /// You should call this every frame (either at the start or the end) to ensure that you have the latest state of each button press. + /// Calls to any method won't change until you call this. pub fn update(&mut self) { self.previous = self.current; self.current = !unsafe { BUTTON_INPUT.read_volatile() }; } + /// Returns [Tri::Positive] if right is pressed, [Tri::Negative] if left is pressed and [Tri::Zero] if neither or both are pressed. + /// This is the normal behaviour you'll want if you're using orthogonal inputs. #[must_use] pub fn x_tri(&self) -> Tri { let left = self.is_pressed(Button::LEFT); @@ -70,6 +130,8 @@ impl ButtonController { (left, right).into() } + /// Returns [Tri::Positive] if down is pressed, [Tri::Negative] if up is pressed and [Tri::Zero] if neither or both are pressed. + /// This is the normal behaviour you'll want if you're using orthogonal inputs. #[must_use] pub fn y_tri(&self) -> Tri { let up = self.is_pressed(Button::UP); @@ -78,6 +140,7 @@ impl ButtonController { (up, down).into() } + /// Returns true if all the buttons specified in `keys` are pressed. #[must_use] pub fn vector(&self) -> Vector2D where @@ -121,11 +184,32 @@ impl ButtonController { (currently_pressed & keys) != 0 } + /// Returns true if all the buttons specified in `keys` are not pressed. Equivalent to `!is_pressed(keys)`. #[must_use] pub fn is_released(&self, keys: Button) -> bool { !self.is_pressed(keys) } + /// Returns true if all the buttons specified in `keys` went from not pressed to pressed in the last frame. + /// Very useful for menu navigation or selection if you want the players actions to only happen for one frame. + /// + /// # Example + /// ```no_run,rust + /// # #![no_std] + /// use agb::input::{Button, ButtonController}; + /// + /// # fn main() { + /// let mut button_controller = ButtonController::new(); + /// + /// loop { + /// button_controller.update(); + /// + /// if button_controller.is_just_pressed(Button::A) { + /// // A button was just pressed, maybe select the currently selected item + /// } + /// } + /// # } + /// ``` #[must_use] pub fn is_just_pressed(&self, keys: Button) -> bool { let current = u32::from(self.current); @@ -134,6 +218,8 @@ impl ButtonController { ((current & keys) != 0) && ((previous & keys) == 0) } + /// Returns true if all the buttons specified in `keys` went from pressed to not pressed in the last frame. + /// Very useful for menu navigation or selection if you want players actions to only happen for one frame. #[must_use] pub fn is_just_released(&self, keys: Button) -> bool { let current = u32::from(self.current);