Pancake Cat
Overview
Walkthrough
Initialize the Project
Begin by creating a new project called pancake-cat
:
turbo init pancake-cat
This initializes a Rust project with the following structure:
pancake-cat/ # 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.
Create a sprites
Folder
Inside your project directory, create a folder named sprites
. This folder will contain all your game sprites.
your-project-dir/ # Your project's root directory.
βββ sprites/ # The directory of your sprite assets.
βββ src/ # The directory of your code.
β βββ lib.rs # The main file for the game.
βββ Cargo.toml # Rust project manifest.
βββ turbo.toml # Turbo configuration.
Add Sprite Assets
Add the following files to the sprites
directory.
Run the Game
At this point, we can run our game and leave it running as we make changes.
turbo run -w pancake-cat
Game State Initialization
Define the initial state of your game:
turbo::init! {
struct GameState {
frame: u32,
last_munch_at: u32,
cat_x: f32,
cat_y: f32,
cat_r: f32,
pancakes: Vec<struct Pancake {
x: f32,
y: f32,
vel: f32,
radius: f32,
}>,
score: u32,
} = Self {
frame: 0,
last_munch_at: 0,
cat_x: 128.0,
cat_y: 112.0,
cat_r: 8.0,
pancakes: vec![],
score: 0,
}
}
Update the Game Loop
Use the Turbo game loop to run your game logic:
turbo::go!({
let mut state = GameState::load();
// The code in the following steps will go here
state.save();
});
Cat Movement
Handle player input to move the cat:
if gamepad(0).left.pressed() {
state.cat_x -= 2.;
}
if gamepad(0).right.pressed() {
state.cat_x += 2.;
}
Pancake Generation
Randomly spawn pancakes:
if rand() % 64 == 0 {
let pancake = Pancake {
x: (rand() % 256) as f32,
y: 0.0,
vel: (rand() % 3 + 1) as f32,
radius: (rand() % 10 + 5) as f32,
};
state.pancakes.push(pancake);
}
Pancake Movement & Collision
Move falling pancakes and detect when they're caught:
let cat_center = (state.cat_x + state.cat_r, state.cat_y + state.cat_r);
state.pancakes.retain_mut(|p| {
p.y += p.vel;
let dx = cat_center.0 - (p.x + p.radius);
let dy = cat_center.1 - (p.y + p.radius);
let distance = (dx * dx + dy * dy).sqrt();
let radii_sum = state.cat_r + p.radius;
let radii_diff = (state.cat_r - p.radius).abs();
if radii_diff <= distance && distance <= radii_sum {
state.score += 1;
state.last_munch_at = state.frame;
false
} else if p.y < 144. + (p.radius * 2.) {
true
} else {
false
}
});
Background Tiles
Draw a simple animated background:
clear(0x00ffffff);
let frame = (state.frame as i32) / 2;
for col in 0..9 {
for row in 0..6 {
let x = ((col * 32 + frame) % (272 + 16)) - 32;
let y = ((row * 32 + frame) % (144 + 16)) - 24;
sprite!("heart", x = x, y = y);
}
}
state.frame += 1;
Drawing the Cat
Render the cat sprite with animation frame logic handled by Turbo:
sprite!("munch_cat", x = state.cat_x - state.cat_r, y = state.cat_y - 16.0);
Drawing the Pancakes
Render the cat sprite with animation frame logic handled by Turbo:
for p in &state.pancakes {
circ!(x = p.x, y = p.y + 1.0, d = p.radius + 2., color = 0x000000aa);
circ!(x = p.x, y = p.y, d = p.radius + 1., color = 0xf4d29cff);
circ!(x = p.x, y = p.y, d = p.radius, color = 0xdba463ff);
}
Speech Bubble
Display a speech bubble with βMUNCH!β when the cat catches a pancake:
if state.frame >= 64 && state.frame.saturating_sub(state.last_munch_at) <= 60 {
rect!(w = 30, h = 10, x = state.cat_x + 32.0, y = state.cat_y);
circ!(d = 10, x = state.cat_x + 28.0, y = state.cat_y);
rect!(w = 10, h = 5, x = state.cat_x + 28.0, y = state.cat_y + 5.0);
circ!(d = 10, x = state.cat_x + 56.0, y = state.cat_y);
text!("MUNCH!", x = state.cat_x + 33.0, y = state.cat_y + 3.0, font = "small", color = 0x000000ff);
}
Score Display
Draw the player's score in the top-left corner:
text!("Score: {}", state.score; x = 10, y = 10, font = "large", color = 0xffffffff);
Conclusion
You just built a fully playable game from scratch using Turbo: input handling, game state, rendering, and collision β all in a tight feedback loop with real-time updates.
You've met the cat. Youβve caught the pancakes. And youβve laid the foundation for every game youβll make next.
Next Steps
- Swap out hearts or pancakes for your own sprite sets
- Add sounds when the cat munches or misses
- Track lives or missed pancakes for added challenge
- Create a title screen and end state
- Export your game to the web using
turbo export