This really quick tutorial is aimed for beginners who want to get started with game/graphics development with Rust and/or Macroquad
Introduction
Hello!
In this really short tutorial, you will learn how to create a simple Clicker with Rust using the Macroquad framework. Macroquad is a simple and easy to use game library for Rust. It supports native desktop apps, WebAssembly, IOS and Android and it is really simple to use.
Perquisites
You must get the follow things down before you proceed with the tutorial:
- Rust and its basics (even though I'll try to explain each and every detail of the code)
Let's Get Started!
First, create a new Rust project, then add this to the cargo.toml
file under the [dependencies]
section:
macroquad = "0.3.25" # at the time of writing this tutorial, this was the version
#you can change the version to the latest stable one
Now, navigate to src/main.rs
file and let's start writing some code!
use macroquad::prelude::*;
#[macroquad::main("Clicker Game")]
async fn main() {
loop {
clear_background(GRAY);
next_frame().await;
}
}
Output:
That's it to get a basic window with a Gray background color, but let's look at it in a little more detail.
use macroquad::prelude::*;
This imports the library that we're going to use (duh).
#[macroquad::main("Clicker Game")]
This tells the program what is the main function, and what the window title should be. Alternatively you can write this in a diferent way for more customizing options:
//snip
fn conf() -> Conf {
Conf {
window_title: "Clicker Game", //this field is not optional!
fullscreen:false,
//you can add other options too, or just use the default ones:
..Default::default()
}
}
//then pass the function to the attribute
#[macroquad::main(conf)]
Moving on.
async fn main() {
loop {
clear_background(GRAY);
next_frame().await;
}
}
We make the main
function async because Macroquad requires async events. Every Macroquad program needs to have a main game loop, we define it with the loop
keyword.
clear_background(GRAY)
function tells the program to clear the screen background to the color Gray. There are other colors too, such as RED, GREEN, BLACK, WHITE, SKYBLUE, BLUE, etc. You can pass the color you want to use in the function.
next_frame().await
This line tells the program to wait till the next frame is done. Without this, the program will just crash.
Creating the Circle
Let us first define the variables we will need, the x and y position of the circle, the radius, and the score:
let (x,y) = (screen_width()/2.,screen_height()/2.);
let r = 70.;
let circle = Circle::new(x,y,r);
let mut score = 0;
The first line gets position to the center of the screen. screen_width()
gets the total width of the screen, and screen_height()
gets the total height.
let circle = Circle::new(x,y,r);
Here we create a struct called Circle, which has three values, the x and y position, and the radius. We will be needing them in click detection.
Now to draw the circle:
loop {
clear_background(GRAY);
draw_circle(x,y,r,RED);
next_frame().await;
}
draw_circle()
is a function which draws a circle to the screen. It takes in four values, x ,y, radius and the color.
Your code should now look like this:
use macroquad::prelude::*;
#[macroquad::main("CLicker Game")]
async fn main() {
let (x,y) = (screen_width()/2.,screen_height()/2.);
let r = 70.;
let circle = Circle::new(x,y,r);
let mut score = 0;
loop {
clear_background(GRAY);
draw_circle(x,y,r,RED);
next_frame().await;
}
}
Output:
If it draws a circle on the screen, it'll do!
Detecting Click Events
Let's add some basic click detection working. The way that we're doing in this tutorial is to make a smaller circle struct (of radius 1) and use the .intersect()
method on the smaller mouse circle and the main circle struct which we created before. The .intersect()
method takes in another struct of the same type, and returns a bool value. If they intersect at any point, it returns true, else it returns false. (Note: there's another way of checking for click on a circular object too with the include()
method with takes a Vec2 value. I've used a different approach because it seems easier to understand for beginners.)
Code:
//snip
loop {
...
if is_mouse_button_pressed(MouseButton::Left) {
let (mouse_x,mouse_y) = mouse_position();
let mouse_circ = Circle::new(mouse_x,mouse_y,1.);
if mouse_circ.intersect(&circle) {
score += 1;
}
}
...
}
is_mouse_button_pressed
is a function which checks if a certain mouse button is pressed and returns a bool value. MouseButton
is an enum which contains the values for Left mouse button, the Right mouse button and the Middle mouse button, and the Unknown variant if the value is not known.
let (mouse_x,mouse_y) = mouse_position();
let mouse_circ = Circle::new(mouse_x,mouse_y,1.);
The first line gets the mouse position at the time of calling that event and stores in the tuple values. We now create the mouse circle with the mouse position and the radius of 1.
(Note that: 1.
is equal to 1.00
. The radius is an f32 value).
if mouse_circ.intersect(&circle) {
score += 1;
}
Now we use the intersect function, and if it does intersect, we add the score value with 1. You can change the increment value to whatever you want.
Displaying Title And Score
To draw text, Macroquad provides us with the draw_text()
function. It takes in the text to display, the x and y positions, the font size and the color of the text.
Add this inside the loop:
//snip
draw_text("Clicker Game",screen_width()/2.-100.,100.,50.,WHITE);
This draws the text "Clicker Game" to the top of the screen.
Displaying the score:
draw_text(format!("Clicks: {}",score).as_str(),screen_width()/2.-100.,500.,50.,WHITE);
We first concatenate the score variable with some other text and use the as_str()
method because draw_text()
accepts only an str
value and not a String
value. We also set the y position to somewhere below the circle, in this case, 500.
And That's It!
You've successfully created a clicker game in Rust! Now just run your project using cargo run
.
Here's the full code:
use macroquad::prelude::*;
#[macroquad::main("CLicker Game")]
async fn main() {
let (x,y) = (screen_width()/2.,screen_height()/2.);
let r = 70.;
let circle = Circle::new(x,y,r);
let mut score = 0;
loop {
clear_background(GRAY);
if is_mouse_button_pressed(MouseButton::Left) {
let (mouse_x,mouse_y) = mouse_position();
let mouse_circ = Circle::new(mouse_x,mouse_y,1.);
if circle.overlaps(&mouse_circ){
score+=1;
}
}
draw_text("Clicker Game",screen_width()/2.-100.,100.,50.,WHITE);
draw_text(format!("Clicks: {}",score).as_str(),screen_width()/2.-100.,500.,50.,WHITE);
draw_circle(x,y,r,RED);
next_frame().await;
}
}
Output:
If there are any corrections, please do inform me.
I will make a part 2 with adding sounds and other stuff. If I don't, remind me!
Good Bye 👋
Other Useful Links:
Macroquad Official Website
Macroquad docs.rs
Macroquad Github
Top comments (2)
The
circle.intersects(&self, &other)
method is no longer present. Instead, try usingcircle.overlaps(&self, &other)
.Awesome! I'd never heard Rust library of his before!!! Thanks a ton