Sunjay Varma
Link to slides: sunjay.dev/learn-game-dev/workshop/
Short URL: goo.gl/sCv2aR
Link to slides: sunjay.dev/learn-game-dev/workshop/
Short URL: goo.gl/sCv2aR
When you ask questions, you are helping:
Professional compiler enthusiast
developer?
Senior-level web developer?
Software architect?
Machine learning / Data scientist?
Indie game developer?
These pictures are from ~10 years ago!
Helping indie game developers create high quality pixel art.
Website: protoart.me
Sign up on our website to get early access & updates!
This workshop is about learning the process of developing a game. Don't worry too much about the final result!
Things to remember as you develop your game:
Hyperloop
Game Loop
Is there an event?
Yes
No
Handle the event
Waits for an event
Traditional UI Application
Game Loop
Is there an event?
Yes
No
Handle the event
Waits for an event
Is there an event?
Yes
No
Handle the event
Update the game state
Keeps going
Traditional UI Application
Game Loop
// Run forever (or until the user exits)
loop {
// Handle ALL the events that are available
// **right now**, or just keep going
handleEvents();
// Update the state of players, enemies, etc.
update();
// Draw the entire current state of the game
render();
}
Complete the following steps:
cargo new
Before we can do this...
We need to do this
Important: You will need to enable the "image" feature of the sdl2 crate in Cargo.toml.
(Make sure you have the SDL2_Image development libraries installed)
[dependencies]
[dependencies.sdl2]
version = "0.32.1"
default-features = false
features = ["image"]
Repository examples directory:
The sdl2 crate documentation:
The sdl2 crate documentation (with "image" feature):
Sprite/Frame
Animation
Looks like walking
Screen Coordinates
World Coordinates
Complete the following steps:
Down
Left
Right
Up
Frame 0
Frame 1
Frame 2
Complete the following steps:
Complete the following steps:
Image source: xkcd.com/1616 XKCD "Lunch"
All of us in this workshop right now
Image source: xkcd.com/1906/ XKCD "Making Progress"
(in one slide)
ID | Position | Velocity | Sprite | Animation |
---|---|---|---|---|
0 | (3,-4) | 1 Up | 0 | frame 1 |
1 | (-17,8) | -1 Left | 1 | |
2 | (-1,0) | 0 Right | ||
... | ... | ... | ... | ... |
Entities
Components
Created before game loop starts
Systems
Physics
Animator
Game AI
Keyboard
Called during "update" step
Each system processes only the columns it needs
Passed in
Updated
Executes in parallel
Grouping state into a single component:
Splitting state across multiple components:
/// The current position of a given entity
#[derive(Component, Debug)]
#[storage(VecStorage)]
struct Position(Point);
/// The current speed and direction of a given entity
#[derive(Component, Debug)]
#[storage(VecStorage)]
struct Velocity { speed: i32, direction: Direction }
#[derive(Component, Debug)]
#[storage(VecStorage)]
struct Sprite {
/// The specific spritesheet to render from
spritesheet: usize,
/// The current region of the spritesheet to be rendered
region: Rect,
}
#[derive(Component, Debug)]
#[storage(VecStorage)]
struct MovementAnimation {
// The current frame in the animation of the entity's direction
current_frame: usize,
up_frames: Vec<Sprite>,
down_frames: Vec<Sprite>,
left_frames: Vec<Sprite>,
right_frames: Vec<Sprite>,
}
Complete the following steps:
Resources: slide-rs.github.io/specs/04_resources.html
Marker Components: slide-rs.github.io/specs/11_advanced_component.html
#[derive(Component, Debug, Default)]
#[storage(NullStorage)]
pub struct KeyboardControlled;
pub enum MovementCommand { // set during event handling
Stop,
Move(Direction),
}
pub struct Keyboard;
impl<'a> System<'a> for Keyboard {
type SystemData = (
ReadExpect<'a, Option<MovementCommand>>,
ReadStorage<'a, KeyboardControlled>,
WriteStorage<'a, Velocity>,
);
fn run(&mut self, mut data: Self::SystemData) {
// ...
}
}
// Type alias for the data needed by the renderer
pub type SystemData<'a> = (
ReadStorage<'a, Position>,
ReadStorage<'a, Sprite>,
);
pub fn render(
canvas: &mut WindowCanvas,
background: Color,
textures: &[Texture],
data: SystemData,
) -> Result<(), String> {
// ...
}
fn main() {
// ...
let mut world = World::new();
dispatcher.setup(&mut world.res);
renderer::SystemData::setup(&mut world.res);
// ...
loop {
// ...
render(&mut canvas, /*...*/, world.system_data())?;
// ...
}
}
Complete the following steps:
Complete the following steps:
let player_bounds = Rect::new(0, 0, 5, 5);
let enemy_bounds = Rect::new(1, 1, 6, 6);
println!("{:?}", player_bounds.intersection(enemy_bounds));
Intersection
No Intersection
Complete the following steps:
Complete the following steps:
Complete the following steps:
For further help on your game:
Rust Users Forum: users.rust-lang.org
Follow me on Twitter: twitter.com/sunjay03
Link to slides: sunjay.dev/learn-game-dev/workshop/
Short URL: goo.gl/sCv2aR