agb_eb_ext 0.25.3

AGB Extension methods
Documentation
use agb::fixnum::{Vector2D, vec2};
use agb::input::{Button, ButtonController};

#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    /// Direction currently held, or `None`
    ///
    /// If several are held, priority is Up > Down > Left > Right
    pub fn from_input(buttons: &ButtonController) -> Option<Direction> {
        if buttons.is_pressed(Button::Up) {
            Some(Direction::Up)
        } else if buttons.is_pressed(Button::Down) {
            Some(Direction::Down)
        } else if buttons.is_pressed(Button::Left) {
            Some(Direction::Left)
        } else if buttons.is_pressed(Button::Right) {
            Some(Direction::Right)
        } else {
            None
        }
    }

    /// Direction pressed this frame, or `None`
    ///
    /// If several were pressed, priority is Up > Down > Left > Right
    pub fn from_recent_input(buttons: &ButtonController) -> Option<Direction> {
        if buttons.is_just_pressed(Button::Up) {
            Some(Direction::Up)
        } else if buttons.is_just_pressed(Button::Down) {
            Some(Direction::Down)
        } else if buttons.is_just_pressed(Button::Left) {
            Some(Direction::Left)
        } else if buttons.is_just_pressed(Button::Right) {
            Some(Direction::Right)
        } else {
            None
        }
    }

    /// The direction facing the other way
    #[inline]
    pub const fn opposite(self) -> Direction {
        match self {
            Direction::Up => Direction::Down,
            Direction::Down => Direction::Up,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
        }
    }

    /// Unit vector for this direction (y grows downwards)
    #[inline]
    pub const fn to_vector(self) -> Vector2D<i32> {
        match self {
            Direction::Up => vec2(0, -1),
            Direction::Down => vec2(0, 1),
            Direction::Left => vec2(-1, 0),
            Direction::Right => vec2(1, 0),
        }
    }

    /// `true` for `Left` and `Right`
    #[inline]
    pub const fn is_horizontal(self) -> bool {
        matches!(self, Direction::Left | Direction::Right)
    }

    /// `true` for `Up` and `Down`
    #[inline]
    pub const fn is_vertical(self) -> bool {
        !self.is_horizontal()
    }
}

impl From<Direction> for Vector2D<i32> {
    fn from(value: Direction) -> Self {
        value.to_vector()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test_case]
    fn opposite_and_vector(_gba: &mut agb::Gba) {
        for dir in [
            Direction::Up,
            Direction::Down,
            Direction::Left,
            Direction::Right,
        ] {
            assert_eq!(dir.opposite().opposite(), dir);
            assert_eq!(dir.to_vector() + dir.opposite().to_vector(), vec2(0, 0));
            assert_ne!(dir.is_horizontal(), dir.is_vertical());
        }
        assert_eq!(Direction::Up.to_vector(), vec2(0, -1));
        assert_eq!(Vector2D::from(Direction::Right), vec2(1, 0));
    }
}