improve inputs
This commit is contained in:
parent
4ccd38580f
commit
cdfb1188ee
25
crates/core/src/c_button.rs
Normal file
25
crates/core/src/c_button.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct CButton {
|
||||
pub pressed: bool,
|
||||
pub released: bool,
|
||||
pub down: bool,
|
||||
pub hold_frames: u32,
|
||||
}
|
||||
|
||||
impl CButton {
|
||||
pub fn begin_frame(&mut self, is_down_now: bool) {
|
||||
let was_down = self.down;
|
||||
self.down = is_down_now;
|
||||
|
||||
// Detecta transições
|
||||
self.pressed = !was_down && self.down;
|
||||
self.released = was_down && !self.down;
|
||||
|
||||
// Atualiza contador de frames
|
||||
if self.down {
|
||||
self.hold_frames = self.hold_frames.saturating_add(1);
|
||||
} else {
|
||||
self.hold_frames = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
pub mod machine;
|
||||
pub mod peripherals;
|
||||
mod color;
|
||||
mod c_button;
|
||||
|
||||
pub use machine::Machine;
|
||||
pub use color::Color;
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use crate::peripherals::{Gfx, Input, Touch};
|
||||
use crate::peripherals::{Gfx, InputSignals, Pad, Touch};
|
||||
use crate::Color;
|
||||
|
||||
/// PROMETEU "hardware lógico" (v0).
|
||||
/// O Host alimenta INPUT/TOUCH e chama `step_frame()` em 60Hz.
|
||||
pub struct Machine {
|
||||
pub gfx: Gfx,
|
||||
pub input: Input,
|
||||
pub pad: Pad,
|
||||
pub touch: Touch,
|
||||
pub frame_index: u64,
|
||||
}
|
||||
@ -17,7 +17,7 @@ impl Machine {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
gfx: Gfx::new(Self::W, Self::H),
|
||||
input: Input::default(),
|
||||
pad: Pad::default(),
|
||||
touch: Touch::default(),
|
||||
frame_index: 0,
|
||||
}
|
||||
@ -25,21 +25,21 @@ impl Machine {
|
||||
|
||||
/// "Contrato de frame" do PROMETEU (Template Method sem loop).
|
||||
/// O Host controla tempo/event loop; o Core define a sequência do frame.
|
||||
pub fn step_frame(&mut self) {
|
||||
self.begin_frame();
|
||||
pub fn step_frame(&mut self, signals: &InputSignals) {
|
||||
self.begin_frame(signals);
|
||||
self.tick(); // futuro: executa cartucho/VM
|
||||
self.end_frame(); // present/housekeeping
|
||||
}
|
||||
|
||||
/// Início do frame: zera flags transitórias.
|
||||
pub fn begin_frame(&mut self) {
|
||||
pub fn begin_frame(&mut self, signals: &InputSignals) {
|
||||
self.frame_index += 1;
|
||||
|
||||
// Flags transitórias do TOUCH devem durar 1 frame.
|
||||
self.touch.begin_frame();
|
||||
self.touch.begin_frame(signals);
|
||||
|
||||
// Se você quiser input com pressed/released depois:
|
||||
// self.input.begin_frame();
|
||||
self.pad.begin_frame(signals);
|
||||
}
|
||||
|
||||
/// Lógica do frame (demo hardcoded por enquanto).
|
||||
@ -48,7 +48,7 @@ impl Machine {
|
||||
|
||||
let (x, y) = self.demo_pos();
|
||||
|
||||
let color = if self.input.a_down || self.touch.down {
|
||||
let color = if self.pad.a.down || self.touch.f.down {
|
||||
Color::rgb(0x00, 0xFF, 0x00)
|
||||
} else {
|
||||
Color::rgb(0xFF, 0x40, 0x40)
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct Input {
|
||||
pub up: bool,
|
||||
pub down: bool,
|
||||
pub left: bool,
|
||||
pub right: bool,
|
||||
|
||||
pub a_down: bool,
|
||||
pub b_down: bool,
|
||||
|
||||
pub start: bool,
|
||||
pub select: bool,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub fn begin_frame(&mut self) {
|
||||
// No v0, nada a fazer.
|
||||
// No futuro: a_pressed/a_released, etc.
|
||||
}
|
||||
}
|
||||
26
crates/core/src/peripherals/input_signal.rs
Normal file
26
crates/core/src/peripherals/input_signal.rs
Normal file
@ -0,0 +1,26 @@
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct InputSignals {
|
||||
// PAD
|
||||
pub up_signal: bool,
|
||||
pub down_signal: bool,
|
||||
pub left_signal: bool,
|
||||
pub right_signal: bool,
|
||||
|
||||
pub a_signal: bool,
|
||||
pub d_signal: bool,
|
||||
pub w_signal: bool,
|
||||
pub s_signal: bool,
|
||||
pub q_signal: bool,
|
||||
pub e_signal: bool,
|
||||
|
||||
pub start_signal: bool,
|
||||
pub select_signal: bool,
|
||||
|
||||
// TOUCH
|
||||
pub t_signal: bool,
|
||||
pub x_pos: i32,
|
||||
pub y_pos: i32,
|
||||
}
|
||||
|
||||
impl InputSignals {
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
mod gfx;
|
||||
mod input;
|
||||
mod pad;
|
||||
mod touch;
|
||||
mod input_signal;
|
||||
|
||||
pub use gfx::Gfx;
|
||||
pub use input::Input;
|
||||
pub use input_signal::InputSignals;
|
||||
pub use pad::Pad;
|
||||
pub use touch::Touch;
|
||||
|
||||
41
crates/core/src/peripherals/pad.rs
Normal file
41
crates/core/src/peripherals/pad.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use crate::c_button::CButton;
|
||||
use crate::peripherals::input_signal::InputSignals;
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct Pad {
|
||||
pub up: CButton,
|
||||
pub down: CButton,
|
||||
pub left: CButton,
|
||||
pub right: CButton,
|
||||
|
||||
pub a: CButton, // ps: square
|
||||
pub d: CButton, // ps: circle
|
||||
pub w: CButton, // ps: triangle
|
||||
pub s: CButton, // ps: cross
|
||||
pub q: CButton, // ps: R
|
||||
pub e: CButton, // ps: L
|
||||
|
||||
pub start: CButton,
|
||||
pub select: CButton,
|
||||
}
|
||||
|
||||
impl Pad {
|
||||
pub fn begin_frame(&mut self, signals: &InputSignals) {
|
||||
self.up.begin_frame(signals.up_signal);
|
||||
self.down.begin_frame(signals.down_signal);
|
||||
self.left.begin_frame(signals.left_signal);
|
||||
self.right.begin_frame(signals.right_signal);
|
||||
|
||||
self.a.begin_frame(signals.a_signal);
|
||||
self.d.begin_frame(signals.d_signal);
|
||||
self.w.begin_frame(signals.w_signal);
|
||||
self.s.begin_frame(signals.s_signal);
|
||||
self.q.begin_frame(signals.q_signal);
|
||||
self.e.begin_frame(signals.e_signal);
|
||||
|
||||
self.start.begin_frame(signals.start_signal);
|
||||
self.select.begin_frame(signals.select_signal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
use crate::c_button::CButton;
|
||||
use crate::peripherals::input_signal::InputSignals;
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct Touch {
|
||||
pub present: bool,
|
||||
pub down: bool,
|
||||
pub pressed: bool,
|
||||
pub released: bool,
|
||||
pub f: CButton,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
}
|
||||
|
||||
impl Touch {
|
||||
/// Flags transitórias devem durar apenas 1 frame.
|
||||
pub fn begin_frame(&mut self) {
|
||||
self.pressed = false;
|
||||
self.released = false;
|
||||
pub fn begin_frame(&mut self, signals: &InputSignals) {
|
||||
self.f.begin_frame(signals.t_signal);
|
||||
self.x = signals.x_pos;
|
||||
self.y = signals.y_pos;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use pixels::{Pixels, SurfaceTexture};
|
||||
use prometeu_core::peripherals::InputSignals;
|
||||
use prometeu_core::Machine;
|
||||
use winit::{
|
||||
application::ApplicationHandler,
|
||||
@ -23,15 +24,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
struct PrometeuApp {
|
||||
window: Option<&'static Window>,
|
||||
pixels: Option<Pixels<'static>>,
|
||||
|
||||
machine: Machine,
|
||||
|
||||
input_signals: InputSignals,
|
||||
|
||||
frame_dt: Duration,
|
||||
next_frame: Instant,
|
||||
|
||||
mouse_down: bool,
|
||||
mouse_just_pressed: bool,
|
||||
mouse_just_released: bool,
|
||||
mouse_pos_fb: (i32, i32),
|
||||
}
|
||||
|
||||
impl PrometeuApp {
|
||||
@ -39,15 +38,11 @@ impl PrometeuApp {
|
||||
Self {
|
||||
window: None,
|
||||
pixels: None,
|
||||
input_signals: InputSignals::default(),
|
||||
machine: Machine::new(),
|
||||
|
||||
frame_dt: Duration::from_nanos(1_000_000_000 / 60),
|
||||
next_frame: Instant::now(),
|
||||
|
||||
mouse_down: false,
|
||||
mouse_just_pressed: false,
|
||||
mouse_just_released: false,
|
||||
mouse_pos_fb: (0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,39 +65,6 @@ impl PrometeuApp {
|
||||
w.request_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
fn map_key(&mut self, code: KeyCode, is_down: bool) {
|
||||
match code {
|
||||
KeyCode::ArrowUp => self.machine.input.up = is_down,
|
||||
KeyCode::ArrowDown => self.machine.input.down = is_down,
|
||||
KeyCode::ArrowLeft => self.machine.input.left = is_down,
|
||||
KeyCode::ArrowRight => self.machine.input.right = is_down,
|
||||
|
||||
// A/B (troque depois como quiser)
|
||||
KeyCode::KeyZ => self.machine.input.a_down = is_down,
|
||||
KeyCode::KeyX => self.machine.input.b_down = is_down,
|
||||
|
||||
KeyCode::Enter => self.machine.input.start = is_down,
|
||||
KeyCode::ShiftLeft | KeyCode::ShiftRight => self.machine.input.select = is_down,
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_touch_in_core(&mut self) {
|
||||
// no desktop, mouse emula touch
|
||||
self.machine.touch.present = true;
|
||||
self.machine.touch.x = self.mouse_pos_fb.0;
|
||||
self.machine.touch.y = self.mouse_pos_fb.1;
|
||||
|
||||
// pressed/released devem durar 1 frame (o core limpa em begin_frame)
|
||||
self.machine.touch.pressed = self.mouse_just_pressed;
|
||||
self.machine.touch.released = self.mouse_just_released;
|
||||
self.machine.touch.down = self.mouse_down;
|
||||
|
||||
self.mouse_just_pressed = false;
|
||||
self.mouse_just_released = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationHandler for PrometeuApp {
|
||||
@ -169,28 +131,42 @@ impl ApplicationHandler for PrometeuApp {
|
||||
WindowEvent::KeyboardInput { event, .. } => {
|
||||
if let PhysicalKey::Code(code) = event.physical_key {
|
||||
let is_down = event.state == ElementState::Pressed;
|
||||
self.map_key(code, is_down);
|
||||
match code {
|
||||
KeyCode::ArrowUp => self.input_signals.up_signal = is_down,
|
||||
KeyCode::ArrowDown => self.input_signals.down_signal = is_down,
|
||||
KeyCode::ArrowLeft => self.input_signals.left_signal = is_down,
|
||||
KeyCode::ArrowRight => self.input_signals.right_signal = is_down,
|
||||
|
||||
// A/B (troque depois como quiser)
|
||||
KeyCode::KeyA => self.input_signals.a_signal = is_down,
|
||||
KeyCode::KeyD => self.input_signals.d_signal = is_down,
|
||||
KeyCode::KeyW => self.input_signals.w_signal = is_down,
|
||||
KeyCode::KeyS => self.input_signals.s_signal = is_down,
|
||||
KeyCode::KeyQ => self.input_signals.q_signal = is_down,
|
||||
KeyCode::KeyE => self.input_signals.e_signal = is_down,
|
||||
|
||||
KeyCode::KeyZ => self.input_signals.start_signal = is_down,
|
||||
KeyCode::ShiftLeft | KeyCode::ShiftRight => self.input_signals.select_signal = is_down,
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
self.mouse_pos_fb = window_to_fb(position.x as f32, position.y as f32, self.window());
|
||||
let v = window_to_fb(position.x as f32, position.y as f32, self.window());
|
||||
self.input_signals.x_pos = v.0;
|
||||
self.input_signals.y_pos = v.1;
|
||||
}
|
||||
|
||||
WindowEvent::MouseInput { state, button, .. } => {
|
||||
if button == MouseButton::Left {
|
||||
match state {
|
||||
ElementState::Pressed => {
|
||||
if !self.mouse_down {
|
||||
self.mouse_down = true;
|
||||
self.mouse_just_pressed = true;
|
||||
}
|
||||
self.input_signals.t_signal = true;
|
||||
}
|
||||
ElementState::Released => {
|
||||
if self.mouse_down {
|
||||
self.mouse_down = false;
|
||||
self.mouse_just_released = true;
|
||||
}
|
||||
self.input_signals.t_signal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -207,11 +183,8 @@ impl ApplicationHandler for PrometeuApp {
|
||||
if now >= self.next_frame {
|
||||
self.next_frame += self.frame_dt;
|
||||
|
||||
// atualiza touch/input no core
|
||||
self.update_touch_in_core();
|
||||
|
||||
// executa 1 frame do PROMETEU
|
||||
self.machine.step_frame();
|
||||
self.machine.step_frame(&self.input_signals);
|
||||
|
||||
// pede redraw
|
||||
self.request_redraw();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user