74 lines
2.0 KiB
Rust

use crate::peripherals::{BlendMode, Gfx, InputSignals, Pad, Touch};
use crate::Color;
/// PROMETEU "hardware lógico" (v0).
/// O Host alimenta INPUT SIGNALS e chama `step_frame()` em 60Hz.
pub struct Machine {
pub gfx: Gfx,
pub pad: Pad,
pub touch: Touch,
pub frame_index: u64,
}
impl Machine {
pub const W: usize = 320;
pub const H: usize = 180;
pub fn new() -> Self {
Self {
gfx: Gfx::new(Self::W, Self::H),
pad: Pad::default(),
touch: Touch::default(),
frame_index: 0,
}
}
/// "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, 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, signals: &InputSignals) {
self.frame_index += 1;
// Flags transitórias do TOUCH devem durar 1 frame.
self.touch.begin_frame(signals);
// Se você quiser input com pressed/released depois:
self.pad.begin_frame(signals);
}
/// Lógica do frame (demo hardcoded por enquanto).
pub fn tick(&mut self) {
self.gfx.clear(Color::rgb(0x10, 0x10, 0x10));
let (x, y) = self.demo_pos();
let color = if self.pad.a.down || self.touch.f.down {
Color::rgb(0x00, 0xFF, 0x00)
} else {
Color::rgb(0xFF, 0x40, 0x40)
};
// game
self.gfx.fill_rect(x, y, 20, 20, color);
// smoke
self.gfx.fill_rect_blend(140, 0, 40, 180, Color::gray_scale(0x88), BlendMode::Half)
}
/// Final do frame: troca buffers.
pub fn end_frame(&mut self) {
self.gfx.present();
}
fn demo_pos(&self) -> (i32, i32) {
let x = (self.frame_index % 300) as i32;
let y = (self.pad.a.hold_frames % 160) as i32;
(x, y)
}
}