feat(snake): 8 steps/s on fixed-period clock (draw time no longer adds to step)
This commit is contained in:
@@ -13,7 +13,9 @@ use libkos::syscall;
|
|||||||
use server_framework::Encode;
|
use server_framework::Encode;
|
||||||
use display_server::protocol::DisplayRequest;
|
use display_server::protocol::DisplayRequest;
|
||||||
|
|
||||||
const TICK_DELAY: u64 = 5_000_000;
|
/// Steps a second; QEMU virt's timebase is 10 MHz.
|
||||||
|
const STEPS_PER_SECOND: u64 = 8;
|
||||||
|
const TICK_DELAY: u64 = 10_000_000 / STEPS_PER_SECOND;
|
||||||
const MAX_RENDER_CMDS: usize = 140;
|
const MAX_RENDER_CMDS: usize = 140;
|
||||||
|
|
||||||
/// The display server, which the shell hands over because snake's manifest
|
/// The display server, which the shell hands over because snake's manifest
|
||||||
@@ -53,6 +55,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
// Takes focus; keys are polled every tick, the signal only wakes it.
|
// Takes focus; keys are polled every tick, the signal only wakes it.
|
||||||
let _ = libkos::display::subscribe(display_ep(), alarm, types::badge::Badge::new(1 << 1));
|
let _ = libkos::display::subscribe(display_ep(), alarm, types::badge::Badge::new(1 << 1));
|
||||||
|
let mut clock = Clock::new(alarm);
|
||||||
let mut snake = Snake::new();
|
let mut snake = Snake::new();
|
||||||
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_CMDS];
|
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_CMDS];
|
||||||
|
|
||||||
@@ -71,12 +74,12 @@ fn main() {
|
|||||||
flush();
|
flush();
|
||||||
// Any key leaves.
|
// Any key leaves.
|
||||||
while next_input() == Input::None {
|
while next_input() == Input::None {
|
||||||
wait_tick(alarm);
|
clock.wait_tick();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_tick(alarm);
|
clock.wait_tick();
|
||||||
if handle_input(&mut snake) == Input::Quit {
|
if handle_input(&mut snake) == Input::Quit {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -126,17 +129,31 @@ fn handle_input(snake: &mut Snake) -> Input {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sleeps until the next tick on `alarm`, instead of spinning. Keys
|
/// The game's clock: a step every `TICK_DELAY`, counted from the last
|
||||||
/// signal it too (snake has one notification), so it waits again until
|
/// step's deadline, so the time drawing takes does not slow it down.
|
||||||
/// the tick is really due.
|
struct Clock {
|
||||||
fn wait_tick(alarm: CapSlot) {
|
alarm: CapSlot,
|
||||||
let deadline = syscall::get_time().raw() + TICK_DELAY;
|
next: u64,
|
||||||
if syscall::set_timer(alarm, Ticks::from_raw(deadline)).is_err() {
|
}
|
||||||
return;
|
|
||||||
|
impl Clock {
|
||||||
|
fn new(alarm: CapSlot) -> Self {
|
||||||
|
Self { alarm, next: syscall::get_time().raw() }
|
||||||
}
|
}
|
||||||
while syscall::get_time().raw() < deadline {
|
|
||||||
if syscall::wait(alarm).is_err() {
|
/// Sleeps until the next step is due, instead of spinning. Keys
|
||||||
|
/// signal `alarm` too (snake has one notification), so it waits again
|
||||||
|
/// until the step really is due.
|
||||||
|
fn wait_tick(&mut self) {
|
||||||
|
// After a stall, carry on from now rather than rushing to catch up.
|
||||||
|
self.next = (self.next + TICK_DELAY).max(syscall::get_time().raw());
|
||||||
|
if syscall::set_timer(self.alarm, Ticks::from_raw(self.next)).is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
while syscall::get_time().raw() < self.next {
|
||||||
|
if syscall::wait(self.alarm).is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user