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 machine;
|
||||||
pub mod peripherals;
|
pub mod peripherals;
|
||||||
mod color;
|
mod color;
|
||||||
|
mod c_button;
|
||||||
|
|
||||||
pub use machine::Machine;
|
pub use machine::Machine;
|
||||||
pub use color::Color;
|
pub use color::Color;
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
use crate::peripherals::{Gfx, Input, Touch};
|
use crate::peripherals::{Gfx, InputSignals, Pad, Touch};
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
|
|
||||||
/// PROMETEU "hardware lógico" (v0).
|
/// PROMETEU "hardware lógico" (v0).
|
||||||
/// O Host alimenta INPUT/TOUCH e chama `step_frame()` em 60Hz.
|
/// O Host alimenta INPUT/TOUCH e chama `step_frame()` em 60Hz.
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
pub gfx: Gfx,
|
pub gfx: Gfx,
|
||||||
pub input: Input,
|
pub pad: Pad,
|
||||||
pub touch: Touch,
|
pub touch: Touch,
|
||||||
pub frame_index: u64,
|
pub frame_index: u64,
|
||||||
}
|
}
|
||||||
@ -17,7 +17,7 @@ impl Machine {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
gfx: Gfx::new(Self::W, Self::H),
|
gfx: Gfx::new(Self::W, Self::H),
|
||||||
input: Input::default(),
|
pad: Pad::default(),
|
||||||
touch: Touch::default(),
|
touch: Touch::default(),
|
||||||
frame_index: 0,
|
frame_index: 0,
|
||||||
}
|
}
|
||||||
@ -25,21 +25,21 @@ impl Machine {
|
|||||||
|
|
||||||
/// "Contrato de frame" do PROMETEU (Template Method sem loop).
|
/// "Contrato de frame" do PROMETEU (Template Method sem loop).
|
||||||
/// O Host controla tempo/event loop; o Core define a sequência do frame.
|
/// O Host controla tempo/event loop; o Core define a sequência do frame.
|
||||||
pub fn step_frame(&mut self) {
|
pub fn step_frame(&mut self, signals: &InputSignals) {
|
||||||
self.begin_frame();
|
self.begin_frame(signals);
|
||||||
self.tick(); // futuro: executa cartucho/VM
|
self.tick(); // futuro: executa cartucho/VM
|
||||||
self.end_frame(); // present/housekeeping
|
self.end_frame(); // present/housekeeping
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Início do frame: zera flags transitórias.
|
/// 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;
|
self.frame_index += 1;
|
||||||
|
|
||||||
// Flags transitórias do TOUCH devem durar 1 frame.
|
// 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:
|
// 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).
|
/// Lógica do frame (demo hardcoded por enquanto).
|
||||||
@ -48,7 +48,7 @@ impl Machine {
|
|||||||
|
|
||||||
let (x, y) = self.demo_pos();
|
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)
|
Color::rgb(0x00, 0xFF, 0x00)
|
||||||
} else {
|
} else {
|
||||||
Color::rgb(0xFF, 0x40, 0x40)
|
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 gfx;
|
||||||
mod input;
|
mod pad;
|
||||||
mod touch;
|
mod touch;
|
||||||
|
mod input_signal;
|
||||||
|
|
||||||
pub use gfx::Gfx;
|
pub use gfx::Gfx;
|
||||||
pub use input::Input;
|
pub use input_signal::InputSignals;
|
||||||
|
pub use pad::Pad;
|
||||||
pub use touch::Touch;
|
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)]
|
#[derive(Default, Clone, Copy, Debug)]
|
||||||
pub struct Touch {
|
pub struct Touch {
|
||||||
pub present: bool,
|
pub f: CButton,
|
||||||
pub down: bool,
|
|
||||||
pub pressed: bool,
|
|
||||||
pub released: bool,
|
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Touch {
|
impl Touch {
|
||||||
/// Flags transitórias devem durar apenas 1 frame.
|
/// Flags transitórias devem durar apenas 1 frame.
|
||||||
pub fn begin_frame(&mut self) {
|
pub fn begin_frame(&mut self, signals: &InputSignals) {
|
||||||
self.pressed = false;
|
self.f.begin_frame(signals.t_signal);
|
||||||
self.released = false;
|
self.x = signals.x_pos;
|
||||||
|
self.y = signals.y_pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
|
use prometeu_core::peripherals::InputSignals;
|
||||||
use prometeu_core::Machine;
|
use prometeu_core::Machine;
|
||||||
use winit::{
|
use winit::{
|
||||||
application::ApplicationHandler,
|
application::ApplicationHandler,
|
||||||
@ -23,15 +24,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
struct PrometeuApp {
|
struct PrometeuApp {
|
||||||
window: Option<&'static Window>,
|
window: Option<&'static Window>,
|
||||||
pixels: Option<Pixels<'static>>,
|
pixels: Option<Pixels<'static>>,
|
||||||
|
|
||||||
machine: Machine,
|
machine: Machine,
|
||||||
|
|
||||||
|
input_signals: InputSignals,
|
||||||
|
|
||||||
frame_dt: Duration,
|
frame_dt: Duration,
|
||||||
next_frame: Instant,
|
next_frame: Instant,
|
||||||
|
|
||||||
mouse_down: bool,
|
|
||||||
mouse_just_pressed: bool,
|
|
||||||
mouse_just_released: bool,
|
|
||||||
mouse_pos_fb: (i32, i32),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrometeuApp {
|
impl PrometeuApp {
|
||||||
@ -39,15 +38,11 @@ impl PrometeuApp {
|
|||||||
Self {
|
Self {
|
||||||
window: None,
|
window: None,
|
||||||
pixels: None,
|
pixels: None,
|
||||||
|
input_signals: InputSignals::default(),
|
||||||
machine: Machine::new(),
|
machine: Machine::new(),
|
||||||
|
|
||||||
frame_dt: Duration::from_nanos(1_000_000_000 / 60),
|
frame_dt: Duration::from_nanos(1_000_000_000 / 60),
|
||||||
next_frame: Instant::now(),
|
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();
|
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 {
|
impl ApplicationHandler for PrometeuApp {
|
||||||
@ -169,28 +131,42 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
WindowEvent::KeyboardInput { event, .. } => {
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
if let PhysicalKey::Code(code) = event.physical_key {
|
if let PhysicalKey::Code(code) = event.physical_key {
|
||||||
let is_down = event.state == ElementState::Pressed;
|
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, .. } => {
|
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, .. } => {
|
WindowEvent::MouseInput { state, button, .. } => {
|
||||||
if button == MouseButton::Left {
|
if button == MouseButton::Left {
|
||||||
match state {
|
match state {
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
if !self.mouse_down {
|
self.input_signals.t_signal = true;
|
||||||
self.mouse_down = true;
|
|
||||||
self.mouse_just_pressed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ElementState::Released => {
|
ElementState::Released => {
|
||||||
if self.mouse_down {
|
self.input_signals.t_signal = false;
|
||||||
self.mouse_down = false;
|
|
||||||
self.mouse_just_released = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,11 +183,8 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
if now >= self.next_frame {
|
if now >= self.next_frame {
|
||||||
self.next_frame += self.frame_dt;
|
self.next_frame += self.frame_dt;
|
||||||
|
|
||||||
// atualiza touch/input no core
|
|
||||||
self.update_touch_in_core();
|
|
||||||
|
|
||||||
// executa 1 frame do PROMETEU
|
// executa 1 frame do PROMETEU
|
||||||
self.machine.step_frame();
|
self.machine.step_frame(&self.input_signals);
|
||||||
|
|
||||||
// pede redraw
|
// pede redraw
|
||||||
self.request_redraw();
|
self.request_redraw();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user