Ever dreamed of building your own game? In this Rust game development series, we’ll use the games development library Macroquad to create a classic Breakout game – step by step, from a blank window to smashing bricks!
(All code for this series can be found here)
Why a Lot of Developers Wanted to be Game Developers
Many developers are where they are today because, growing up they wanted to be game developers. And although, in practice, working in the games industry can be less lucrative and much more difficult to be in than regular software development, games software still has an unmistakable allure.
It’s a field where creativity meets technical prowess, allowing developers to craft worlds, tell stories, and engage players in unique experiences. And developing it, at least on a small scale, can be both challenging as it requires you to engineer complex real-time software, but also immensely satisfying due to its immediate feedback, visual appeal and overall cool factor.
However, historically the path to becoming a game developer has often been fraught with high barriers to entry, such as complex tools, steep learning curves, and the need for substantial resources. Over the past decade or so, however, this has become less so thanks to game engines such as Unreal and Unity.
Game Engines – what do they do?
To get a game on screen, you need:
- A Programming Language: To write the logic of your game.
- Graphics API: Like OpenGL or Vulkan, to handle rendering.
- Sound System: To manage audio playback.
- Input Handling: To capture user interactions.
- Game Loop: A structure to keep the game running smoothly.
A game engine abstracts all of these components away behind a much more user-friendly framework. Graphics, for instance, can be very challenging if you’re attempting to write a game engine from scratch, with just getting a triangle up on screen with Vulkan taking hundreds of lines of shader and rendering code. A game engine like Unreal, however, offers a way to do this relatively simply.
However, even Unreal and Unity offer a lot of complexity, and can be overkill for smaller projects. They also come with their own learning curves, and can be restrictive in terms of what you can do with them without a lot of customization. This is where Macroquad comes in.
Why Rust, and Why Macroquad?
Rust, as a low level systems programming language, is perfect for games development. Other languages such as Java or Python, which have managed memory, can be used to write games but often come with performance penalties so you have to “fight the garbage collector”.
Rust on the other hand, has no such problem, and also offers the speed and flexibility of C++, but without the memory safety issues and a much more modern toolset. However, even with Rust, writing a game engine from scratch can be a daunting task and just like C++, writing a graphics engine can be a complex and time-consuming task. What if you just want to make games?
This is where Macroquad comes in. Macroquad, based on the Miniquad graphics framework, is a game framework for Rust that allows you to get up and running with a game quickly in a matter of a few lines of code, but if you feel the need to also offers low-level API access to be able to do things like use your own shaders.
It’s the ideal balance between simplicity, and the power of a full game engine. This is why I’ve chosen to use Macroquad for this series on game development!
The First Step to Writing a Simple Game
In this series, we’re going to be writing a simple game with Macroquad. However, the words “simple game” don’t mean boring – it involves rendering things to the screen, handling user input, updating the game state and handling collisions – all of which are interesting challenges.
The best thing about Macroquad is that it contains a lot of excellent pre-written code that makes these tasks much simpler than if you were writing them from scratch, and also small enough to fit into a short blog tutorial series rather than a book.
The intention of this series is to get you from this:
to this:
while showing you how to get all the things you need for a game up and running using Macroquad, and then move on to bigger and better projects. So, let’s get started with…
Your First Window with Macroquad
So it’s time to start out on our gamedev journey with some simple, but yet powerful Macroquad code! Getting your first window up with Macroquad is a straightforward process:
use macroquad::prelude::*;
#[macroquad::main("My First Window")]
async fn main() {
loop {
clear_background(WHITE);
// Draw some text to verify everything's working
draw_text("Hello, Macroquad!", 10.0, 50.0, 30.0, DARKGRAY);
next_frame().await
}
}
So what does this code do? Using macroquad::prelude::*, we import all necessary components from Macroquad.
We then define the main function with the #[macroquad::main] macro, which sets up the game loop.
If you’re wondering why the fn main is async fn main in Macroquad, the fn main function is defined as an async fn main because Macroquad uses Rust’s async/await system to manage its cross-platform game loop in a non-blocking way.
This design choice addresses specific challenges related to how games need to run across different platforms, particularly on the web (WebAssembly/WASM), Android, and desktop environments.
In the loop, we clear the screen with a white background each frame, draw some text to show something, and then wait for the next frame with next_frame().await, ensuring that the game loop runs smoothly. Building this with Cargo gets you…
This seems simplistic, but then that is the true appeal of Macroquad! If you were writing this from scratch, you would have to spend time using a GUI library such as winit to get something up on screen, and even then that might be just a window, with far more work needed to get it into shape to be used for games.
However, with this simple example, you’ve bridged from having nothing to getting a functional window where you can start layering your game logic, graphics, and interactions – a perfect base from which to start our game development journey!
Come back next time, when we get the visual components of our Breakout game – the bat, the ball and the blocks – rendered on screen and start bringing our game to life!