use bevy::{
input::gamepad::{
GamepadConnection, GamepadConnectionEvent, RawGamepadButtonChangedEvent, RawGamepadEvent,
},
prelude::*,
};
#[derive(Default)]
pub struct AgbInputPlugin;
impl Plugin for AgbInputPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(ButtonController::new())
.add_systems(PreUpdate, update_gamepad);
}
fn finish(&self, app: &mut App) {
let world = app.world_mut();
let gamepad = world.spawn(GameBoyGamepad {}).id();
let event = GamepadConnectionEvent::new(
gamepad,
GamepadConnection::Connected {
name: "GameBoy Advance Gamepad".to_string(),
vendor_id: Some(0x057E),
product_id: None,
},
);
world.write_message::<RawGamepadEvent>(event.clone().into());
world.write_message::<GamepadConnectionEvent>(event);
}
}
#[derive(Resource, Deref, DerefMut)]
pub struct ButtonController(agb::input::ButtonController);
impl ButtonController {
#[must_use]
fn new() -> Self {
Self(agb::input::ButtonController::new())
}
}
#[derive(Component)]
#[non_exhaustive]
pub struct GameBoyGamepad {}
fn update_gamepad(
mut manager: ResMut<ButtonController>,
mut events: MessageWriter<RawGamepadEvent>,
mut button_events: MessageWriter<RawGamepadButtonChangedEvent>,
gamepad: Single<Entity, With<GameBoyGamepad>>,
) {
manager.update();
let gamepad = gamepad.into_inner();
agb::input::Button::all()
.iter()
.filter_map(agb_to_bevy_button)
.filter_map(|(agb_button, bevy_button)| {
manager
.is_just_pressed(agb_button)
.then_some(1.)
.or(manager.is_just_released(agb_button).then_some(0.))
.map(|value| RawGamepadButtonChangedEvent::new(gamepad, bevy_button, value))
})
.for_each(|event| {
events.write(event.into());
button_events.write(event);
});
}
const fn agb_to_bevy_button(
button: agb::input::Button,
) -> Option<(agb::input::Button, GamepadButton)> {
use agb::input::Button;
match button {
Button::A => Some((button, GamepadButton::East)),
Button::B => Some((button, GamepadButton::South)),
Button::SELECT => Some((button, GamepadButton::Select)),
Button::START => Some((button, GamepadButton::Start)),
Button::RIGHT => Some((button, GamepadButton::DPadRight)),
Button::LEFT => Some((button, GamepadButton::DPadLeft)),
Button::UP => Some((button, GamepadButton::DPadUp)),
Button::DOWN => Some((button, GamepadButton::DPadDown)),
Button::R => Some((button, GamepadButton::RightTrigger)),
Button::L => Some((button, GamepadButton::LeftTrigger)),
_ => None,
}
}