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
        );
    }
);