Cheatsheet
Starting a Project
To create a new project, you can run the command turbo init <PROJECT-NAME>
. For example, we could run the following command if we want to make a project called hello-world
:
turbo init hello-world
This will create a new project directory with the following structure:
hello-world/ # Your project's root directory.
├── src/ # The directory of your code.
│ └── lib.rs # The main file for the game.
├── Cargo.toml # Rust project manifest.
└── turbo.toml # Turbo configuration.
Once the project has been initialized, you can run it with turbo run -w <PROJECT-NAME>
. For example, to run the hello-world
project we created with the previous command:
turbo run -w hello-world
Updating Your Config
When you initialize a project, you'll see a file called turbo.toml
in your project directory. If you open that file, you should see something like this:
name = "hello-world"
version = "0.1.0"
authors = ["Your Name"]
description = "An awesome game made in Turbo!"
[canvas]
width = 256
height = 144
Managing Assets
Assets go special subdirectories within the project directory. All asset folders are optional, so if you don't have a certain kind of asset, there is no need to add an empty directory.
your-project-dir/ # Your project's root directory.
├── sprites/ # The directory of your sprite assets.
├── fonts/ # The directory of your font assets.
├── audio/ # The directory of your audio assets.
├── shaders/ # The directory of your shaders.
├── src/ # The directory of your code.
│ └── lib.rs # The main file for the game.
├── Cargo.toml # Rust project manifest.
└── turbo.toml # Turbo configuration.
Drawing Shapes
// Draw a 20x40px blue rectangle
rect!(w = 20, h = 40, x = 70, y = 70, color = 0xff00ffff)
// Draw an 16px diameter magenta circle
circ!(d = 16, x = 120, y = 64, color = 0xff00ffff)
Displaying Text
// Basic text
text!("Hello, world!");
// Customized text with specified position, color, and font size
text!(
"Greetings, earthlings >:3",
x = 30,
y = 40,
color = 0x00ff00ff,
font = "small"
);
Handling Mouse & Touch Controls
// The pointer control works for both mouse and touch inputs
let p = pointer();
// Get the pointer x position
let pointer_x = p.x;
// Get the pointer y position
let pointer_y = p.y;
// Check if the pointer was just pressed this frame (mouse click or touch)
if pointer.just_pressed() {
// ...
}
Handling Gamepad Controls
// Get player 1's gamepad (Pass a 1 instead of a 0 for player 2's gamepad)
let gp = gamepad(0);
// Check if the `Up` button was just pressed this frame.
if gp.up.just_pressed() {
// ...
}
// Check if the `Down` button is currently being pressed.
if gp.down.just_pressed() {
// ...
}
// Check if the `A` button was just released this frame.
if gp.a.just_released() {
// ...
}
// Check if the `B` button is currently not being pressed.
if gp.b.released() {
// ...
}
Generating Random Numbers
// Get a random number
let n = rand();
// Check if a random number is even
let is_even = rand() % 2 == 0;
// Check if a random number is odd
let is_odd = rand() % 2 != 0;
// Get a random number between 1-100
let n = 1 + (rand() % 100);
// Probability Ranges
match n {
1..=10 => { ... } // 10% chance
11..=50 => { ... } // 40% chance
_ => { ... } // 50% chance
}
Tracking Time
In most cases, using the current game "tick" is sufficient for working with time in a game. It starts at 0
and increases by one each time a new frame is rendered.
let t = tick();
When you need an actual unix timestamp, you can get it, we've also got you covered:
let timestamp = time::now();
Adjusting the Camera
// Get the camera position
let (x, y, z) = camera::xyz();
// Set the camera position
// The position you set here is the center of the viewport in pixels. By default the camera starts at half of the width and height of your game's resolution.
camera::set_xy(100, 100);
// Move the camera position relative to the current camera position
camera::move_x(5.0);
camera::move_y(8.0);
// Reset the camera to its original position
camera::reset(100,100,10,20);
Debugging
Turbo's logging system prints directly to your terminal, making it easy to trace variable values, game state, and behavior during runtime. Whether you're narrowing down a bug or watching a value evolve, log!
is your go-to for visibility without disruption.
// Log a static message
log!("o hai!");
// Log a single value
let some_var = "foo";
log!("one value: {:?}", some_var);
// Log multiple values
let another_var = 42;
log!("multiple values: {:?} {:?}", some_var, another_var);
// Log game state
let state = GameState::load();
log!("My game state = {:?}", state);
Initializing Game State
Turbo provides a straightforward way to initialize the standard game state using the turbo::init!
macro. This macro is essential for defining and setting up the game state before entering the main game loop:
turbo::init! {
// 1. Define the GameState struct.
struct GameState {
screen: enum Screen {
Title,
Level,
},
x_position: i32,
y_position: i32,
} = {
// 2. Return the GameState's initial value.
// You can also run initializaion code here before returning the state.
Self {
screen: Screen::Title,
x_position: 30,
y_position: 40,
}
}
}
Running the Game Loop
Turbo games run at 60 fps and the typical game loop should follow this pattern:
turbo::go!({
// 1. Load State
// This hydrates state from the previous loop.
// The initial state's initial value will load on the first loop.
let mut state = GameState::load();
// 2. Update State
// The bulk of your game's logic goes here. Mutate state as-needed.
// 3. Save State
// The final thing you should do in your game loop is save your game state.
// This serializes state and persists it in memory so it doesn't get lost while hot-reloading
state.save();
});