Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 42

Setting Up Your Game Window and Render Loop

Recommended resources

Hello! Welcome back to our chess project.

In our last lesson, you successfully added the macroquad graphics library to our project using Cargo. This was a crucial first step into the world of graphical applications in Rust. Our project now has access to a powerful toolkit for drawing and user interaction.

Today, we'll put that library to use. We're moving from the command line to a graphical window. The goal of this lesson is to create a game window and set up a main rendering loop. This loop is the beating heart of any game; it's a continuous cycle that draws everything you see on the screen, frame by frame.

By the end of this lesson, you will have replaced our console-based "Hello, world!" with a graphical window and understand the basic structure of a macroquad application.

1. The Anatomy of a Macroquad App

Before we write any code, let's get a high-level overview. A macroquad application has a few key ingredients:

  • A special attribute to mark our main function as the entry point for the game.
  • An async main function. This is a requirement for macroquad to handle different platforms (like desktop and web) smoothly.
  • An infinite loop that runs for every frame of the game.
  • A function call inside the loop that tells macroquad to update the screen.

Let's watch a short video that puts these pieces together.

Rust breakout game tutorial

This video by Tantan is a great, concise demonstration of setting up a basic macroquad application. It will show you exactly the code we need to get a window on the screen.

Watch from the timestamp 00:29 to 01:16. Pay attention to how the main function is structured, the use of the loop, and the next_frame() call.

As you saw, it only takes a few lines of code to get a window up and running. Now, let's do it ourselves and then break down what each line means.


2. Hands-On: Creating Your Game Window

It's time to replace the code in your src/main.rs file. For now, we will set aside all our existing chess logic. Don't worry, we'll bring it back in later lessons once we have the graphical foundation in place.

  1. Open src/main.rs: Open your project's main source file. It probably just contains a println!("Hello, world!"); line.

  2. Replace the code: Delete everything in src/main.rs and replace it with the following code.

    use macroquad::prelude::*;
    
    
    
    
    #[macroquad::main("Chess")]
    async fn main() {
        loop {
            clear_background(LIGHTGRAY);
    
            // All of our game's drawing and logic will go here in the future
    
            next_frame().await;
        }
    }
    
  3. Run the project: Go to your terminal and run the command:

    cargo run
    

After a moment of compiling, you should see a new window appear with the title "Chess" and a light gray background. It's empty, but it's a window that you created! You can close it to stop the program.


3. Understanding the Code

You've successfully created a window. Now, let's understand how it works. The code is simple, but each part plays a vital role.

Your first Macroquad app

The official Macroquad documentation provides an excellent explanation for the starter code we just used. This will clarify the purpose of each line.

Read the section titled 'Description of the application'. It breaks down the use statement, the #[macroquad::main] attribute, the game loop, and the next_frame() function.

Let's summarize the key points from that reading:

  • use macroquad::prelude::*;: This line imports the most common functions and types from the macroquad library, so we can use things like clear_background and LIGHTGRAY directly.
  • #[macroquad::main("Chess")]: This is a Rust macro. It's a special piece of code that writes more code for you at compile time. This specific macro from macroquad sets up the window with the title "Chess" and prepares the platform-specific code needed to run your main function.
  • async fn main(): The async keyword is part of Rust's concurrency system. macroquad uses it to manage the game loop in a non-blocking way, which is especially important for web-based games (a cool feature of macroquad!) and ensures your game runs smoothly without freezing the operating system.
  • loop { ... }: This is our main rendering loop. Everything inside this loop will be executed repeatedly, once for each frame. If your game runs at 60 frames per second (FPS), this loop runs 60 times every second.
  • clear_background(LIGHTGRAY);: This is our first drawing command. It tells macroquad to fill the entire window with a specific color. Even if you don't call this, macroquad clears the screen with black by default at the start of each frame.
  • next_frame().await;: This is arguably the most important line. It tells macroquad that you are done with all your drawing commands for the current frame. The .await pauses your main function until it's time to draw the next frame, effectively syncing your loop to the screen's refresh rate and preventing your CPU from running at 100% unnecessarily.

Quick Challenge

The resource you just read mentioned a challenge. Let's try it!
Go back to your code and change LIGHTGRAY to a different color. You can try RED, BLUE, GREEN, or even DARKPURPLE. Run the program again to see your change. This simple exercise reinforces the idea that the code inside the loop directly controls what you see on the screen.


Conclusion

Fantastic! You've made the leap from a text-only console program to a graphical application. You now have a window and a running render loop, which is the fundamental structure for your entire chess game.

Key Takeaways:

  • The #[macroquad::main("Window Title")] macro is used to create a window and start the game.
  • The game's logic and drawing commands are placed inside an infinite loop {}, which represents the main rendering loop.
  • The async fn main() and next_frame().await combination is how macroquad manages the frame-by-frame execution in a platform-independent way.
  • Functions like clear_background() are used inside the loop to draw to the screen.

Preview of the Next Lesson

Our window is currently just an empty gray box. In the next lesson, we'll start making it look like a chess game. We will learn how to draw shapes, specifically rectangles, to draw the 8x8 chessboard with its alternating colored squares. This will be our first major step in visualizing the game state.