Smooth movement

Screenshot

Since Macroquad will draw frames as quickly as possible, we need to check how much time has passed between each update to determine how far the circle should move. Otherwise, our game will run at different speeds on different computers, depending on how quickly they can run the application. The specific framerate will depend on your computer; if Vsync is enabled it may be locked to 30 or 60 frames per second.

Implementation

We will expand the application and add a constant that determines how quickly the circle should move. We call the constant MOVEMENT_SPEED and assign the value 200.0. If the circle moves too fast or too slow, we can decrease or increase this value.

    const MOVEMENT_SPEED: f32 = 200.0;

Time between frames

Now we will use the function get_frame_time() to get the time in seconds that has passed since the last frame. We assign this value to a variable called delta_time that we will use later.

        let delta_time = get_frame_time();

Update movement

When the variables x and y are updated, we will multiply the values of the constant MOVEMENT_SPEED by the variable delta_time to get how far the circle should move during this frame.

        if is_key_down(KeyCode::Right) {
            x += MOVEMENT_SPEED * delta_time;
        }
        if is_key_down(KeyCode::Left) {
            x -= MOVEMENT_SPEED * delta_time;
        }
        if is_key_down(KeyCode::Down) {
            y += MOVEMENT_SPEED * delta_time;
        }
        if is_key_down(KeyCode::Up) {
            y -= MOVEMENT_SPEED * delta_time;
        }

Limit movement

Finally, we will prevent the circle from moving outside of the window. We use the Macroquad function clamp() to make sure x and y are never below 0 or above the width of the window.

        x = clamp(x, 0.0, screen_width());
        y = clamp(y, 0.0, screen_height());

Info

The clamp() function is used to clamp a value between a minimum and maximum value. It is part of the Macroquad Math API.

Challenge

Change the constant MOVEMENT_SPEED if the circle is moving too slow or too fast.

What do you need to change to ensure that the entire circle stays within the window when the position is clamped?

Source

The code should now look like this:

use macroquad::prelude::*;

#[macroquad::main("My game")]
async fn main() {
    const MOVEMENT_SPEED: f32 = 200.0;

    let mut x = screen_width() / 2.0;
    let mut y = screen_height() / 2.0;

    loop {
        clear_background(DARKPURPLE);

        let delta_time = get_frame_time();
        if is_key_down(KeyCode::Right) {
            x += MOVEMENT_SPEED * delta_time;
        }
        if is_key_down(KeyCode::Left) {
            x -= MOVEMENT_SPEED * delta_time;
        }
        if is_key_down(KeyCode::Down) {
            y += MOVEMENT_SPEED * delta_time;
        }
        if is_key_down(KeyCode::Up) {
            y -= MOVEMENT_SPEED * delta_time;
        }

        x = clamp(x, 0.0, screen_width());
        y = clamp(y, 0.0, screen_height());

        draw_circle(x, y, 16.0, YELLOW);
        next_frame().await
    }
}

Quiz

Try your knowledge by answering the following quiz before you move on to the next chapter.

Agical