use super::scene::{time_of, Scenes, STEP};
use super::{Game, Keys, Screen};
use crate::clock::FixedStep;
use crate::{Event, Pointer, Terminal};
use std::io;
use std::time::{Instant, SystemTime, UNIX_EPOCH};
const MAX_CATCH_UP: u32 = 5;
pub fn run(game: impl Game + 'static) -> io::Result<()> {
let mut terminal = Terminal::start()?;
terminal.report_mouse_movement()?;
let real = terminal.enable_key_release()?;
let mut keys = Keys::new().real_release(real);
let (width, height) = terminal.size();
let mut screen = Screen::new(width.max(1), height.saturating_sub(1).max(1));
let seed = seed_from_clock();
let mut scenes = Scenes::new(Box::new(game));
let mut pointer = Pointer::default();
let mut clock = FixedStep::new(STEP, MAX_CATCH_UP);
let mut last = Instant::now();
let mut tick = 0u64;
loop {
if let Some(event) = terminal.poll(clock.until_next())? {
match &event {
Event::Key(key) if key.is_ctrl('c') => return Ok(()),
Event::Key(_) | Event::KeyUp(_) => keys.event(&event, time_of(tick)),
Event::Mouse(mouse) => pointer.update(mouse),
_ => {}
}
}
let now = Instant::now();
let due = clock.advance(now.duration_since(last));
last = now;
if due == 0 {
continue;
}
for _ in 0..due {
if !scenes.step(&mut keys, &mut pointer, tick, screen.size(), seed) {
return Ok(());
}
tick += 1;
}
scenes.draw(&mut screen, tick);
terminal.draw(screen.display())?;
}
}
fn seed_from_clock() -> u64 {
match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(elapsed) => elapsed.as_nanos() as u64,
Err(_) => 1,
}
}