How to Use the Macroquad Crate for Simple 2D Games

Macroquad is a lightweight, cross-platform game engine for Rust that simplifies 2D development by providing a single, unified API for graphics, audio, and input without requiring complex build configurations.

Macroquad is a lightweight, cross-platform game engine for Rust that simplifies 2D development by providing a single, unified API for graphics, audio, and input without requiring complex build configurations. You initialize the engine with a custom main function that calls macroquad::main, then implement your game logic inside the update and draw functions, which run on every frame.

Here is a minimal example creating a window with a moving red square that follows the mouse cursor:

use macroquad::prelude::*;

fn main() {
    macroquad::main(game_loop);
}

fn game_loop(mut ctx: &mut macroquad::Macroquad) {
    // Update logic
    let mouse_pos = mouse_position();
    
    // Draw logic
    clear_background(Color::new(0.1, 0.1, 0.1, 1.0));
    
    draw_rectangle(
        mouse_pos.0 - 25.0, 
        mouse_pos.1 - 25.0, 
        50.0, 
        50.0, 
        RED
    );
}

To run this, add macroquad = "0.4" to your Cargo.toml and ensure you have a compatible graphics backend installed (usually handled automatically on most systems). The engine handles the window loop, so you only need to focus on the frame-by-frame state changes.

For a slightly more complex scenario involving asset loading and user input, you can load textures and handle keyboard events directly within the loop. Note that macroquad uses a single-threaded model, so heavy computations should be minimized or offloaded if necessary, though for simple 2D games, the main thread is typically sufficient.

use macroquad::prelude::*;

fn main() {
    macroquad::main(game_loop);
}

fn game_loop(ctx: &mut macroquad::Macroquad) {
    // Static asset loading (only happens once if wrapped in a static or lazy static)
    // For simplicity, we assume a texture is loaded or use a placeholder color
    let mut player_x = 100.0;
    let mut player_y = 100.0;

    // Input handling
    if is_key_pressed(KeyCode::Right) {
        player_x += 5.0;
    }
    if is_key_pressed(KeyCode::Left) {
        player_x -= 5.0;
    }

    // Drawing
    clear_background(BLACK);
    draw_text("Move with Left/Right Arrows", 10.0, 20.0, 20.0, WHITE);
    
    draw_circle(player_x, player_y, 30.0, YELLOW);
}

The crate's prelude module exports the most common functions, keeping imports clean. Since macroquad is designed for rapid prototyping, it abstracts away much of the boilerplate found in lower-level libraries like wgpu or glutin, making it ideal for learning Rust game development or shipping small indie titles quickly. Just remember that because it relies on a single thread for the game loop, performance bottlenecks usually stem from inefficient drawing calls or heavy logic within update rather than threading issues.