Getting Started
Overview
A Turbo game typically has 3 main parts, each controlled by a macro:
- Configuration -
turbo::cfg!
- Initialization -
turbo::init!
- Execution -
turbo::go!
All are optional except for turbo::go!
, but most games will at least want to include game state initialization via turbo::init!
as well.
Configuration
Use the turbo::cfg!
macro to define your game's metadata and configure settings in TOML format:
turbo::cfg! {r#"
name = "Game name"
version = "1.0.0"
author = "game author"
description = "Game description"
[settings]
resolution = [256, 144]
[solana]
http-rpc-url = "http://127.0.0.1:8899"
ws-rpc-url = "ws://127.0.0.1:8900"
"#}
The Solana configuration is required for those who want to interact with Solana in their games. Otherwise, the remaining config fields are optional.
Initialization
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! {
// Define the GameState struct.
struct GameState {
screen: enum Screen {
Title,
Level,
},
x_position: i32,
y_position: i32,
} = {
// Set the struct's initial value.
Self {
screen: Screen::Title,
x_position: 30,
y_position: 40,
}
}
}
- For convenience,
turbo::init!
allows nested struct and enum definitions via the structstruck crate. turbo::init
will derive the following traits for type each defined in the macro:BorshSerialize
,BorshDeserialize
,PartialEq
,Debug
, andClone
.- In development, you can reset the state of the game to its initial state anytime by using a simple keyboard shortcut
Cmd+R
on MacOS/Linux andCtrl+R
on Windows.
Execution
Turbo games run at 60 fps and the typical game loop should typically 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
// 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();
}
If you're building something more along the lines of a visualizer, your game may not have its own state to manage. In this case, all you need is the game logic. You can skip turbo::init!
(and loading/saving game state).