Macro gemini_engine::fps_gameloop
source · macro_rules! fps_gameloop { ($logic:block, $render:block, $fps:expr) => { ... }; ($logic:block, $render:block, $fps:expr, $handle_elapsed:expr) => { ... }; }
Expand description
You can use the fps_gameloop!
macro to avoid writing a lot of boilerplate code. Take this block of code from a program written with gemini
let mut cube = Mesh3D::default_cube();
let FPS = 30.0;
let mut frame_skip = false;
loop {
let now = gameloop::Instant::now();
// Logic
cube.transform.rotation.y += 0.1;
if frame_skip {
frame_skip = false;
} else {
view.clear();
// Rendering
view.blit(&viewport.render(vec![&cube], DisplayMode::Solid), Wrapping::Ignore);
view.display_render().unwrap();
}
let elapsed = now.elapsed();
frame_skip = gameloop::sleep_fps(FPS, Some(elapsed));
}
There’s a lot of very repetitive code here. That’s where this macro comes in. Here is the same block of code, rewritten with fps_gameloop!
:
let mut cube = Mesh3D::default_cube();
let FPS = 30.0;
fps_gameloop!(
{
cube.transform.rotation.y += 0.1;
},
{
view.clear();
view.blit(&viewport.render(vec![&cube], DisplayMode::Solid), Wrapping::Ignore);
view.display_render().unwrap();
},
FPS
);
The code is now a lot less cluttered. This macro accepts three fragments (and an optional fourth fragment). A logic block fragment (contained inside {}
brackets) for code that should run every single frame, a render block fragment for code related to displaying to the terminal (all plots, blits and renders) and a f32
fragment representing the desired frames per second. The fourth optional fragment is to be a function that accepts a Duration
parameter representing the time taken to render everything and a bool
parameter representing whether the last frame was skipped or not. It can be used to, say, print debug info. Here’s an example:
fps_gameloop!(
// -- other f ields --
|elapsed: gameloop::Duration, frame_skip: bool| {
println!(
"Elapsed: {:.2?}µs | Frame skip: {}",
elapsed.as_micros(),
frame_skip
);
}
);