mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +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 bitflags::bitflags;
|
||||||
use core::convert::From;
|
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)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
pub enum Tri {
|
pub enum Tri {
|
||||||
|
/// Right or down
|
||||||
Positive = 1,
|
Positive = 1,
|
||||||
|
/// Unpressed
|
||||||
Zero = 0,
|
Zero = 0,
|
||||||
|
/// Left or up
|
||||||
Negative = -1,
|
Negative = -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,16 +38,27 @@ impl From<(bool, bool)> for Tri {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
/// Represents a button on the GBA
|
||||||
pub struct Button: u32 {
|
pub struct Button: u32 {
|
||||||
|
/// The A button
|
||||||
const A = 1 << 0;
|
const A = 1 << 0;
|
||||||
|
/// The B button
|
||||||
const B = 1 << 1;
|
const B = 1 << 1;
|
||||||
|
/// The SELECT button
|
||||||
const SELECT = 1 << 2;
|
const SELECT = 1 << 2;
|
||||||
|
/// The START button
|
||||||
const START = 1 << 3;
|
const START = 1 << 3;
|
||||||
|
/// The RIGHT button on the D-Pad
|
||||||
const RIGHT = 1 << 4;
|
const RIGHT = 1 << 4;
|
||||||
|
/// The LFET button on the D-Pad
|
||||||
const LEFT = 1 << 5;
|
const LEFT = 1 << 5;
|
||||||
|
/// The UP button on the D-Pad
|
||||||
const UP = 1 << 6;
|
const UP = 1 << 6;
|
||||||
|
/// The DOWN button on the D-Pad
|
||||||
const DOWN = 1 << 7;
|
const DOWN = 1 << 7;
|
||||||
|
/// The R button on the D-Pad
|
||||||
const R = 1 << 8;
|
const R = 1 << 8;
|
||||||
|
/// The L button on the D-Pad
|
||||||
const L = 1 << 9;
|
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;
|
// 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 {
|
pub struct ButtonController {
|
||||||
previous: u16,
|
previous: u16,
|
||||||
current: u16,
|
current: u16,
|
||||||
|
@ -48,6 +101,8 @@ impl Default for ButtonController {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonController {
|
impl ButtonController {
|
||||||
|
/// Create a new ButtonController.
|
||||||
|
/// This is the preferred way to create it.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let pressed = !unsafe { BUTTON_INPUT.read_volatile() };
|
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) {
|
pub fn update(&mut self) {
|
||||||
self.previous = self.current;
|
self.previous = self.current;
|
||||||
self.current = !unsafe { BUTTON_INPUT.read_volatile() };
|
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]
|
#[must_use]
|
||||||
pub fn x_tri(&self) -> Tri {
|
pub fn x_tri(&self) -> Tri {
|
||||||
let left = self.is_pressed(Button::LEFT);
|
let left = self.is_pressed(Button::LEFT);
|
||||||
|
@ -70,6 +130,8 @@ impl ButtonController {
|
||||||
(left, right).into()
|
(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]
|
#[must_use]
|
||||||
pub fn y_tri(&self) -> Tri {
|
pub fn y_tri(&self) -> Tri {
|
||||||
let up = self.is_pressed(Button::UP);
|
let up = self.is_pressed(Button::UP);
|
||||||
|
@ -78,6 +140,7 @@ impl ButtonController {
|
||||||
(up, down).into()
|
(up, down).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if all the buttons specified in `keys` are pressed.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn vector<T>(&self) -> Vector2D<T>
|
pub fn vector<T>(&self) -> Vector2D<T>
|
||||||
where
|
where
|
||||||
|
@ -121,11 +184,32 @@ impl ButtonController {
|
||||||
(currently_pressed & keys) != 0
|
(currently_pressed & keys) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if all the buttons specified in `keys` are not pressed. Equivalent to `!is_pressed(keys)`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_released(&self, keys: Button) -> bool {
|
pub fn is_released(&self, keys: Button) -> bool {
|
||||||
!self.is_pressed(keys)
|
!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]
|
#[must_use]
|
||||||
pub fn is_just_pressed(&self, keys: Button) -> bool {
|
pub fn is_just_pressed(&self, keys: Button) -> bool {
|
||||||
let current = u32::from(self.current);
|
let current = u32::from(self.current);
|
||||||
|
@ -134,6 +218,8 @@ impl ButtonController {
|
||||||
((current & keys) != 0) && ((previous & keys) == 0)
|
((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]
|
#[must_use]
|
||||||
pub fn is_just_released(&self, keys: Button) -> bool {
|
pub fn is_just_released(&self, keys: Button) -> bool {
|
||||||
let current = u32::from(self.current);
|
let current = u32::from(self.current);
|
||||||
|
|
Loading…
Reference in a new issue