feat: implement keyboard controls

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-07-09 19:19:52 -05:00
parent 468f7c0f83
commit 40ca0abb72
3 changed files with 71 additions and 6 deletions

View File

@ -4,8 +4,8 @@ use crate::joypad;
use crate::ppu::Ppu; use crate::ppu::Ppu;
use anyhow::Result; use anyhow::Result;
use gilrs::Gilrs; use gilrs::Gilrs;
use rodio::OutputStreamHandle;
use std::time::Duration; use std::time::Duration;
use winit_input_helper::WinitInputHelper;
pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED); pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED);
pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines
@ -28,19 +28,26 @@ pub fn rom_title(game_boy: &SM83) -> &str {
game_boy.rom_title().unwrap_or(DEFAULT_TITLE) game_boy.rom_title().unwrap_or(DEFAULT_TITLE)
} }
pub fn run(game_boy: &mut SM83, gamepad: &mut Gilrs, pending: Cycle) -> Cycle { pub fn run(
game_boy: &mut SM83,
gamepad: &mut Gilrs,
input: &WinitInputHelper,
pending: Cycle,
) -> Cycle {
let mut elapsed = Cycle::new(0); let mut elapsed = Cycle::new(0);
while elapsed < pending { while elapsed < pending {
elapsed += run_unsynced(game_boy, gamepad); elapsed += run_unsynced(game_boy, gamepad, input);
} }
elapsed elapsed
} }
pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs) -> Cycle { pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs, input: &WinitInputHelper) -> Cycle {
if let Some(event) = gamepad.next_event() { if let Some(event) = gamepad.next_event() {
joypad::handle_gamepad_input(&mut game_boy.joypad_mut(), event); joypad::handle_gamepad_input(game_boy.joypad_mut(), event);
} else {
joypad::handle_keyboard_input(game_boy.joypad_mut(), input);
} }
game_boy.step() game_boy.step()

View File

@ -1,4 +1,5 @@
use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType}; use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType};
use winit_input_helper::WinitInputHelper;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Joypad { pub struct Joypad {
@ -109,6 +110,63 @@ impl ButtonEvent {
} }
} }
pub fn handle_keyboard_input(pad: &mut Joypad, input: &WinitInputHelper) {
use winit::event::VirtualKeyCode;
// TODO: What do I have to do to get a match statement here?
let state = &mut pad.ext;
let irq = &mut pad.interrupt;
if input.key_pressed(VirtualKeyCode::Down) {
state.dpad_down.update(true, irq);
} else if input.key_released(VirtualKeyCode::Down) {
state.dpad_down.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Up) {
state.dpad_up.update(true, irq);
} else if input.key_released(VirtualKeyCode::Up) {
state.dpad_up.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Left) {
state.dpad_left.update(true, irq);
} else if input.key_released(VirtualKeyCode::Left) {
state.dpad_left.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Right) {
state.dpad_right.update(true, irq);
} else if input.key_released(VirtualKeyCode::Right) {
state.dpad_right.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::T) {
state.start.update(true, irq);
} else if input.key_released(VirtualKeyCode::T) {
state.start.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Y) {
state.select.update(true, irq);
} else if input.key_released(VirtualKeyCode::Y) {
state.select.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Z) {
state.south.update(true, irq);
} else if input.key_released(VirtualKeyCode::Z) {
state.south.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::X) {
state.east.update(true, irq);
} else if input.key_released(VirtualKeyCode::X) {
state.east.update(false, irq);
}
}
pub fn handle_gamepad_input(pad: &mut Joypad, event: GamepadEvent) { pub fn handle_gamepad_input(pad: &mut Joypad, event: GamepadEvent) {
use Button::*; use Button::*;
use GamepadEventType::*; use GamepadEventType::*;

View File

@ -127,7 +127,7 @@ fn main() -> Result<()> {
now = Instant::now(); now = Instant::now();
let pending = Cycle::new(delta / gb::emu::SM83_CYCLE_TIME.subsec_nanos()); let pending = Cycle::new(delta / gb::emu::SM83_CYCLE_TIME.subsec_nanos());
cycle_count += gb::emu::run(&mut game_boy, &mut gamepad, pending); cycle_count += gb::emu::run(&mut game_boy, &mut gamepad, &input, pending);
if cycle_count >= gb::emu::CYCLES_IN_FRAME { if cycle_count >= gb::emu::CYCLES_IN_FRAME {
// Draw Frame // Draw Frame