mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
Add a bunch of docs for input
This commit is contained in:
parent
e666ebbd05
commit
dfa70f4335
|
@ -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<T>(&self) -> Vector2D<T>
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue