Building a Simple Snake Game with Rust and SDL2
In this tutorial, we’ll explore how to create a simple snake game using Rust and the SDL2 library. We’ll cover the basics of setting up a Rust project, understanding the SDL2 API, and implementing game logic.
Setting Up Our Rust and SDL2 Project
First, let’s set up our Rust project. We’ll use Cargo, the Rust package manager, to create a new project.
bash
cargo new snake_game
Next, we need to add the SDL2 dependency to our Cargo.toml
file:
toml
[dependencies]
sdl2 = "0.34"
Now, let’s install the SDL2 native development files. On macOS, we can use Homebrew:
bash
brew install sdl2
On Linux (Ubuntu), we can use apt-get:
bash
sudo apt-get install libsdl2-dev
Understanding a Simple SDL Program
Before we dive into our snake game, let’s take a look at a simple SDL program. This will help us understand the basics of the SDL2 API.
Here’s a simple example that creates a window and renders a red background:
“`rust
extern crate sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::VideoSubsystem;
fn main() {
let sdlcontext = sdl2::init().unwrap();
let videosubsystem = sdlcontext.video().unwrap();
let window = videosubsystem.window(“Snake Game”, 800, 600)
.position_centered()
.build()
.unwrap();
let mut canvas = window.into_canvas().build().unwrap();
canvas.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 0));
canvas.clear();
canvas.present();
let mut event_pump = sdl_context.event_pump().unwrap();
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'running;
}
_ => {}
}
}
}
}
“`
This code initializes the SDL2 library, creates a window, and renders a red background. It also sets up an event loop to handle user input.
Writing Our Game Logic
Now that we have a basic understanding of the SDL2 API, let’s start implementing our snake game logic.
We’ll define a GameContext
struct to hold our game state:
“`rust
struct GameContext {
playerposition: Vec
player
food_position: Point,
state: GameState,
}
enum GameState {
Paused,
Playing,
Over,
}
struct Point {
x: i32,
y: i32,
}
“`
We’ll also define some methods to update our game state:
“`rust
impl GameContext {
fn new() -> Self {
// Initialize game state here
}
fn update(&mut self) {
// Update game state here
}
fn handle_input(&mut self, event: Event) {
// Handle user input here
}
}
“`
We’ll implement these methods in the next sections.
Rendering Our Game State
To render our game state, we’ll define a Renderer
struct:
“`rust
struct Renderer {
canvas: Canvas
}
impl Renderer {
fn new(canvas: Canvas
Self { canvas }
}
fn render(&mut self, game_context: