Giorgio Pomettini
ROME - APRIL 13/14 2018
Rust & Gamedev
2013
C#
2013 2017
C# C
2013 2017 2018
C# C C++
C# C++
C# C++
• Memory safety
• Portability (Mono)
C# C++
• Memory safety
• Portability (Mono)
• GC Spikes
C# C++
• Memory safety
• Portability (Mono)
• GC Spikes
• Performance
• Libraries
C# C++
• Memory safety
• Portability (Mono)
• GC Spikes
• Performance
• Libraries
• Segfaults
Why Rust?
Why Rust?
• Guaranteed memory safety (without GC)
Why Rust?
• Guaranteed memory safety (without GC)
• Performance similar to C/C++
Why Rust?
• Guaranteed memory safety (without GC)
• Performance similar to C/C++
• The compiler prevents all data races
Why Rust?
• Guaranteed memory safety (without GC)
• Performance similar to C/C++
• The compiler prevents all data races
• No null checking
Why Rust?
• Guaranteed memory safety (without GC)
• Performance similar to C/C++
• The compiler prevents all data races
• No null checking
• Multiparadigm (Procedural, Functional and OOP*)
Why Rust?
• Guaranteed memory safety (without GC)
• Performance similar to C/C++
• The compiler prevents all data races
• No null checking
• Multiparadigm (Procedural, Functional and OOP*)
• Has an integrated package manager
Why Rust?
• Guaranteed memory safety (without GC)
• Performance similar to C/C++
• The compiler prevents all data races
• No null checking
• Multiparadigm (Procedural, Functional and OOP*)
• Has an integrated package manager
• Great community
Why Rust?
• Guaranteed memory safety (without GC)
• Performance similar to C/C++
• The compiler prevents all data races
• No null checking
• Multiparadigm (Procedural, Functional and OOP*)
• Has an integrated package manager
• Great community
• Release cycle of 6 weeks
Why Rust?
Most loved programming language
by the Stack Overflow community in
2016, 2017 and 2018
Why Rust?
Most loved programming language
by the Stack Overflow community in
2016, 2017 and 2018
A bit of history
A bit of history
•2009 - Graydon Hoare releases Rust 0.1
A bit of history
•2009 - Graydon Hoare releases Rust 0.1
•2010 - Mozilla starts sponsoring Rust
A bit of history
•2009 - Graydon Hoare releases Rust 0.1
•2010 - Mozilla starts sponsoring Rust
•2011 - LLVM support as back-end
A bit of history
•2009 - Graydon Hoare releases Rust 0.1
•2010 - Mozilla starts sponsoring Rust
•2011 - LLVM support as back-end
•2012 - First release of the compiler
A bit of history
•2009 - Graydon Hoare releases Rust 0.1
•2010 - Mozilla starts sponsoring Rust
•2011 - LLVM support as back-end
•2012 - First release of the compiler
•2015 - Rust Stable 1.0
Hello World
$ curl https://sh.rustup.rs -sSf | sh
Hello World
$ cargo new hello_world --bin
Hello World
Hello World
fn main() {
println!("Hello, world!");
}
Hello World
$ cargo run
Hello World
$ cargo run
Compiling hello_world v0.1.0 (file:///path/to/project/hello_world)
Running `target/debug/hello_world`
Hello, world!
Structs
struct Character {
hp: u32,
weapon: Weapon
}
struct Weapon {
name: String,
damage: u32
}
Structs
struct Character {
hp: u32,
weapon: Weapon
}
struct Weapon {
name: String,
damage: u32
}
TypeVariable name
Implementations
impl Character {
fn new() -> Character {
Character {
hp: 0,
weapon: Weapon::new()
}
}
}
impl Weapon {
fn new() -> Weapon {
Weapon {
name: String::from("None"),
damage: 0
}
}
}
Implementations
impl Character {
fn new() -> Character {
Character {
hp: 0,
weapon: Weapon::new()
}
}
}
impl Weapon {
fn new() -> Weapon {
Weapon {
name: String::from("None"),
damage: 0
}
}
}
Logic for Weapon struct
Constructor
Implementations
impl Character {
fn new() -> Character {
Character {
hp: 0,
weapon: Weapon::new()
}
}
}
impl Weapon {
fn new() -> Weapon {
Weapon {
name: String::from("None"),
damage: 0
}
}
}
fn main() {
let player: Character = Character::new();
player.hp = 10;
}
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
}
Variables are immutable by default
fn main() {
...
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword;
}
fn main() {
...
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword;
let mut ally: Character = Character::new();
ally.weapon = sword;
}
fn main() {
...
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword;
let mut ally: Character = Character::new();
ally.weapon = sword;
}
error[E0382]: use of moved value: `sword`
--> src/main.rs:10:19
Ownership (T)
Every value has a single owner at any given time. 



You can move a value from one owner to another, but when a
value’s owner goes away, the value is freed along with it.
Ownership (T)
Sword
Hp
Weapon
Stack
Player
Ally
Hp
Weapon
Name *
Damage
Sword
Hp
Weapon
Stack
Player
Ally
Hp
Weapon
Name *
Damage
Moved
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
}
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
}
I clone the weapon
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
}
I clone the weapon
The original weapon will be moved
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
}
I clone the weapon
The original weapon will be moved
Out of scope: memory erased
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
display_character_hp(player);
}
I want to make a function that displays the player’s hp
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
display_character_hp(player);
}
But the player will be moved here
Borrowing (&T)
Borrowing (&T)
You can borrow a reference to a value. 



Borrowed references are temporary pointers; they allow you to
operate on values you don’t own.
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
display_character_hp(&player);
}
I borrow the Player to the function
fn main() {
let mut player: Character = Character::new();
player.hp = 10;
let mut sword: Weapon = Weapon::new();
sword.damage = 5;
player.weapon = sword.clone();
let mut ally: Character = Character::new();
ally.weapon = sword;
display_character_hp(&player);
}
I borrow the Player to the function
fn display_character_hp(character: &Character)
{
println!("The character has {:?} hps”, character.hp);
}
When I exit the scope Player will be available again
impl Character {
...
fn attack(&self, target: &Character) {
}
}
The function has a reference to itself
in order to get the weapon damage points
impl Character {
...
fn attack(&self, target: &Character) {
}
}
The function has a reference to itself
in order to get the weapon damage points
impl Character {
...
fn attack(&self, target: &Character) {
}
}
And borrows a player in order
to modify its HPs
impl Character {
...
fn attack(&self, target: &Character) {
target.hp -= self.weapon.damage;
}
}
fn main() {
...
display_character_hp(&player);
ally.attack(&player);
}
Plot twist! The ally attacks!
impl Character {
...
fn attack(&self, target: &Character) {
target.hp -= self.weapon.damage;
}
}
fn main() {
...
display_character_hp(&player);
ally.attack(&player);
}
impl Character {
...
fn attack(&self, target: &Character) {
target.hp -= self.weapon.damage;
}
}
error[E0594]: cannot assign to field `target.hp` of immutable binding
--> src/main.rs:38:9
|
37 | fn attack(&self, target: &Character) {
| ---------- use `&mut Character` here to make mutable
38 | target.hp -= self.weapon.damage;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot mutably borrow field of immutable binding
Mutable Borrowing (&mut T)
Mutable Borrowing (&mut T)
You can borrow a mutable reference to a value

Borrowing a mutable reference forbids any 

other access to the value
fn main() {
...
ally.attack(&mut player);
}
impl Character {
...
fn attack(&self, target: &mut Character) {
target.hp -= self.weapon.damage;
}
}
fn main() {
...
ally.attack(&mut player);
}
impl Character {
...
fn attack(&self, target: &mut Character) {
target.hp -= self.weapon.damage;
}
}
Now takes a mutable reference
Was it hard?
• No dangling pointers
Was it hard?
• No dangling pointers

• No memory leaks
Was it hard?
• No dangling pointers

• No memory leaks

• No segfaults
Was it hard?
• No dangling pointers

• No memory leaks

• No segfaults

• No data races
Was it hard?
• No dangling pointers

• No memory leaks

• No segfaults

• No data races

• Performance comparable to C++
Was it hard?
• No dangling pointers

• No memory leaks

• No segfaults

• No data races

• Performance comparable to C++

• Basically if it compiles, it will never break
Was it hard?
Cons of Rust (ATM)
• Tough learning curve
Cons of Rust (ATM)
• Tough learning curve

• Lack of libraries
Cons of Rust (ATM)
• Tough learning curve

• Lack of libraries

• Poor IDEs support
Cons of Rust (ATM)
• Tough learning curve

• Lack of libraries

• Poor IDEs support

• Long compile times
Cons of Rust (ATM)
• Tough learning curve *

• Lack of libraries *

• Poor IDEs support *

• Long compile times *

They’re working on it!
Cons of Rust (ATM)
Crates
Crates
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Giorgio Pomettini <giorgio.pomettini@gmail.com>"]
Cargo.toml
Crates
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Giorgio Pomettini <giorgio.pomettini@gmail.com>"]
[dependencies]
rand = "0.3"
Cargo.toml
Crates
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Giorgio Pomettini <giorgio.pomettini@gmail.com>"]
[dependencies]
rand = "0.3"
extern crate rand;
use rand::Rng;
fn main() {
...
let mut ally: Character = Character::new();
ally.weapon = sword;
ally.weapon.damage = rand::thread_rng().gen_range(0, 10);
}
Cargo.toml
What about the IDE?
What about the IDE?
https://areweideyet.com/
• Syntax Highlighting
• Code Completion
• Code Formatting
• Debugging
What about the IDE?
https://areweideyet.com/
My pick:

❤ VS Code + RLS ❤ • Syntax Highlighting
• Code Completion
• Code Formatting
• Debugging
Who uses Rust in production?
Who uses Rust in production?
Everyday we work with something (partially) built in Rust
Who uses Rust in production?
Everyday we work with something (partially) built in Rust
Who uses Rust in production?
(Gamedev)
Who uses Rust in production?
(Gamedev)
Who uses Rust in production?
(Gamedev)
WAIT! Don’t leave the room yet!
Who uses Rust in production?
(Gamedev)
“Penso che Rust sia il
linguaggio low level più
efficace, pratico e divertente.
Codice legacy a parte ho
finalmente chiuso con C/C++”
Who uses Rust in production?
(Gamedev)
Ho un sogno: entro i
prossimi dieci anni spero
che tutto il nostro codice
nativo sarà in Rust […]
Who uses Rust in production?
(Gamedev)
“Rustifizzare” le
codebase diventerà
presto un obbligo di
sicurezza per chi fa
platform development
Games written in Rust
Games written in Rust
SHAR (WIP, Steam) *
A futuristic soccer game with deterministic physics synchronized between clients
Games written in Rust
Citybound (WIP) *
Like SimCity but with a million people on the screen at the same time,
each one with a different routine
Games written in Rust
A Snake’s Tale (Steam, App Store, Play Store) *
A colorful puzzle game. Runs on every PC and mobile platform
Games written in Rust
WitchBrook (WIP, Steam + Console) *
From the same authors of Stardew Valley. First pure Rust console game
Where should I start?
Where should I start?
•Rust Book
Where should I start?
•Rust Book
•Into_Rust();
Where should I start?
•Rust Book
•Into_Rust();
•Programming Rust
Where should I start?
•Rust Book
•Into_Rust();
•Programming Rust
•#rust-beginners IRC
Where should I start?
•Rust Book
•Into_Rust();
•Programming Rust
•#rust-beginners IRC
•/r/Rust Reddit
Where should I start?
•Rust Book
•Into_Rust();
•Programming Rust
•#rust-beginners IRC
•/r/Rust Reddit
•Clippy (code linter)
Where should I start?
http://arewegameyet.com/
Game Engines
Piston GGEZ Amethyst
Pros
Cons
Game Engines
Piston GGEZ Amethyst
Pros
Modular

Lot of components

Support for 2d and 3d
Cons
Not beginner friendly
Game Engines
Piston GGEZ Amethyst
Pros
Modular

Lot of components

Support for 2d and 3d
Inspired by Love2D

Easy to learn

Lightweight
Cons
Not beginner friendly Few components
Game Engines
Piston GGEZ Amethyst
Pros
Modular

Lot of components

Support for 2d and 3d
Inspired by Love2D

Easy to learn

Lightweight
Data-driven

Good for prototyping

Support for 2d and 3d
Cons
Not beginner friendly Few components Poor documentation
Let’s make an Idle Game!
Let’s make an Idle Game!
// I load GGEZ
extern crate ggez;
use ggez::{GameResult, Context, ContextBuilder};
use ggez::graphics::{self, DrawMode, Point2, Font, Text};
use ggez::conf;
use ggez::event::{self, MouseButton};
struct MainState {
font: Font,
text: Text,
cookies: u32
}
Let’s make an Idle Game!
impl MainState {
// Context Init. The context holds the hardware state
// GameResult is a value of type Result used for error handling
fn new(ctx: &mut Context) -> GameResult<MainState> {
// Load the text
let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf", 32)?;
// Draw the empty text
let text = graphics::Text::new(ctx, "", &font)?;
let s = MainState { font, text, cookies: 0 };
// If we got no errors I return the state
Ok(s)
}
}
Let’s make an Idle Game!
impl MainState {
// Context Init. The context holds the hardware state
// GameResult is a value of type Result used for error handling
fn new(ctx: &mut Context) -> GameResult<MainState> {
// Load the text
let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf", 32)?;
// Draw the empty text
let text = graphics::Text::new(ctx, "", &font)?;
let s = MainState { font, text, cookies: 0 };
// If we got no errors I return the state
Ok(s)
}
}
In Rust errors are values (Result)
Let’s make an Idle Game!
impl event::EventHandler for MainState {
fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
// I draw the cookie amount on screen
self.text = graphics::Text::new(ctx, &format!("Cookies: {}", self.cookies), &self.font)?;
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
// I clear the screen
graphics::clear(ctx);
// I draw the text
graphics::draw(ctx, &self.text, Point2::new(250.0, 150.0), 0.0)?;
// I draw a pseudo cookie
graphics::circle(ctx, DrawMode::Fill, Point2::new(400.0, 400.0), 100.0, 2.0)?;
// Blit
graphics::present(ctx);
Ok(())
}
fn mouse_button_down_event(&mut self, _ctx: &mut Context, _button: MouseButton, _x: i32, _y: i32) {
// Every time I click the screen I get one cookie
self.cookies += 1;
}
}
Let’s make an Idle Game!
impl event::EventHandler for MainState {
fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
// I draw the cookie amount on screen
self.text = graphics::Text::new(ctx, &format!("Cookies: {}", self.cookies), &self.font)?;
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
// I clear the screen
graphics::clear(ctx);
// I draw the text
graphics::draw(ctx, &self.text, Point2::new(250.0, 150.0), 0.0)?;
// I draw a pseudo cookie
graphics::circle(ctx, DrawMode::Fill, Point2::new(400.0, 400.0), 100.0, 2.0)?;
// Blit
graphics::present(ctx);
Ok(())
}
fn mouse_button_down_event(&mut self, _ctx: &mut Context, _button: MouseButton, _x: i32, _y: i32) {
// Every time I click the screen I get one cookie
self.cookies += 1;
}
}
This is a trait. It’s like a C# interface
Let’s make an Idle Game!
pub fn main() {
// Context Builder will set up the window
let cb = ContextBuilder::new("Cookie Clicker", "Pomettini")
.window_setup(conf::WindowSetup::default().title("Cookie Clicker"))
.window_mode(conf::WindowMode::default().dimensions(800, 600));
// I initialize the context
let ctx = &mut cb.build().unwrap();
// I set MainState as the starting state
let state = &mut MainState::new(ctx).unwrap();
// I run the event loop
event::run(ctx, state).unwrap();
}
Let’s make an Idle Game!
But… is there Unity for Rust?
But… is there Unity for Rust?
https://github.com/GodotNativeTools/godot-rust
Let’s make our Game Engine!
Let’s make our Game Engine!
C Bindings Pure Rust
Let’s make our Game Engine!
C Bindings Pure Rust
Window + Input sdl2 glutin (GLFW)
Let’s make our Game Engine!
C Bindings Pure Rust
Window + Input sdl2 glutin (GLFW)
Graphics gl-rs (OpenGL) glium
Let’s make our Game Engine!
C Bindings Pure Rust
Window + Input sdl2 glutin (GLFW)
Graphics gl-rs (OpenGL) glium
Audio alto (OpenAL) rodio
Let’s make our Game Engine!
C Bindings Pure Rust
Window + Input sdl2 glutin (GLFW)
Graphics gl-rs (OpenGL) glium
Audio alto (OpenAL) rodio
Physics nphysics
Let’s make our Game Engine!
C Bindings Pure Rust
Window + Input sdl2 glutin (GLFW)
Graphics gl-rs (OpenGL) glium
Audio alto (OpenAL) rodio
Physics nphysics
ezing (Easing), pathfinding (Pathfinding), tiled (Tilemaps)
Thank you
Special thanks to the Rust Roma community
and in particular to Enrico Risa
• Mail: giorgio.pomettini@gmail.com

• Sito web: www.videogio.co

• Twitter: @dreamquest

Rust & Gamedev

  • 1.
    Giorgio Pomettini ROME -APRIL 13/14 2018 Rust & Gamedev
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
    C# C++ • Memorysafety • Portability (Mono)
  • 9.
    C# C++ • Memorysafety • Portability (Mono) • GC Spikes
  • 10.
    C# C++ • Memorysafety • Portability (Mono) • GC Spikes • Performance • Libraries
  • 11.
    C# C++ • Memorysafety • Portability (Mono) • GC Spikes • Performance • Libraries • Segfaults
  • 12.
  • 13.
    Why Rust? • Guaranteedmemory safety (without GC)
  • 14.
    Why Rust? • Guaranteedmemory safety (without GC) • Performance similar to C/C++
  • 15.
    Why Rust? • Guaranteedmemory safety (without GC) • Performance similar to C/C++ • The compiler prevents all data races
  • 16.
    Why Rust? • Guaranteedmemory safety (without GC) • Performance similar to C/C++ • The compiler prevents all data races • No null checking
  • 17.
    Why Rust? • Guaranteedmemory safety (without GC) • Performance similar to C/C++ • The compiler prevents all data races • No null checking • Multiparadigm (Procedural, Functional and OOP*)
  • 18.
    Why Rust? • Guaranteedmemory safety (without GC) • Performance similar to C/C++ • The compiler prevents all data races • No null checking • Multiparadigm (Procedural, Functional and OOP*) • Has an integrated package manager
  • 19.
    Why Rust? • Guaranteedmemory safety (without GC) • Performance similar to C/C++ • The compiler prevents all data races • No null checking • Multiparadigm (Procedural, Functional and OOP*) • Has an integrated package manager • Great community
  • 20.
    Why Rust? • Guaranteedmemory safety (without GC) • Performance similar to C/C++ • The compiler prevents all data races • No null checking • Multiparadigm (Procedural, Functional and OOP*) • Has an integrated package manager • Great community • Release cycle of 6 weeks
  • 21.
    Why Rust? Most lovedprogramming language by the Stack Overflow community in 2016, 2017 and 2018
  • 22.
    Why Rust? Most lovedprogramming language by the Stack Overflow community in 2016, 2017 and 2018
  • 23.
    A bit ofhistory
  • 24.
    A bit ofhistory •2009 - Graydon Hoare releases Rust 0.1
  • 25.
    A bit ofhistory •2009 - Graydon Hoare releases Rust 0.1 •2010 - Mozilla starts sponsoring Rust
  • 26.
    A bit ofhistory •2009 - Graydon Hoare releases Rust 0.1 •2010 - Mozilla starts sponsoring Rust •2011 - LLVM support as back-end
  • 27.
    A bit ofhistory •2009 - Graydon Hoare releases Rust 0.1 •2010 - Mozilla starts sponsoring Rust •2011 - LLVM support as back-end •2012 - First release of the compiler
  • 28.
    A bit ofhistory •2009 - Graydon Hoare releases Rust 0.1 •2010 - Mozilla starts sponsoring Rust •2011 - LLVM support as back-end •2012 - First release of the compiler •2015 - Rust Stable 1.0
  • 29.
    Hello World $ curlhttps://sh.rustup.rs -sSf | sh
  • 30.
    Hello World $ cargonew hello_world --bin
  • 31.
  • 32.
    Hello World fn main(){ println!("Hello, world!"); }
  • 33.
  • 34.
    Hello World $ cargorun Compiling hello_world v0.1.0 (file:///path/to/project/hello_world) Running `target/debug/hello_world` Hello, world!
  • 35.
    Structs struct Character { hp:u32, weapon: Weapon } struct Weapon { name: String, damage: u32 }
  • 36.
    Structs struct Character { hp:u32, weapon: Weapon } struct Weapon { name: String, damage: u32 } TypeVariable name
  • 37.
    Implementations impl Character { fnnew() -> Character { Character { hp: 0, weapon: Weapon::new() } } } impl Weapon { fn new() -> Weapon { Weapon { name: String::from("None"), damage: 0 } } }
  • 38.
    Implementations impl Character { fnnew() -> Character { Character { hp: 0, weapon: Weapon::new() } } } impl Weapon { fn new() -> Weapon { Weapon { name: String::from("None"), damage: 0 } } } Logic for Weapon struct Constructor
  • 39.
    Implementations impl Character { fnnew() -> Character { Character { hp: 0, weapon: Weapon::new() } } } impl Weapon { fn new() -> Weapon { Weapon { name: String::from("None"), damage: 0 } } }
  • 40.
    fn main() { letplayer: Character = Character::new(); player.hp = 10; }
  • 41.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; } Variables are immutable by default
  • 42.
    fn main() { ... letmut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword; }
  • 43.
    fn main() { ... letmut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword; let mut ally: Character = Character::new(); ally.weapon = sword; }
  • 44.
    fn main() { ... letmut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword; let mut ally: Character = Character::new(); ally.weapon = sword; } error[E0382]: use of moved value: `sword` --> src/main.rs:10:19
  • 45.
  • 46.
    Every value hasa single owner at any given time. 
 
 You can move a value from one owner to another, but when a value’s owner goes away, the value is freed along with it. Ownership (T)
  • 47.
  • 48.
  • 49.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; }
  • 50.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; } I clone the weapon
  • 51.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; } I clone the weapon The original weapon will be moved
  • 52.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; } I clone the weapon The original weapon will be moved Out of scope: memory erased
  • 53.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; display_character_hp(player); } I want to make a function that displays the player’s hp
  • 54.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; display_character_hp(player); } But the player will be moved here
  • 55.
  • 56.
    Borrowing (&T) You canborrow a reference to a value. 
 
 Borrowed references are temporary pointers; they allow you to operate on values you don’t own.
  • 57.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; display_character_hp(&player); } I borrow the Player to the function
  • 58.
    fn main() { letmut player: Character = Character::new(); player.hp = 10; let mut sword: Weapon = Weapon::new(); sword.damage = 5; player.weapon = sword.clone(); let mut ally: Character = Character::new(); ally.weapon = sword; display_character_hp(&player); } I borrow the Player to the function fn display_character_hp(character: &Character) { println!("The character has {:?} hps”, character.hp); } When I exit the scope Player will be available again
  • 59.
    impl Character { ... fnattack(&self, target: &Character) { } }
  • 60.
    The function hasa reference to itself in order to get the weapon damage points impl Character { ... fn attack(&self, target: &Character) { } }
  • 61.
    The function hasa reference to itself in order to get the weapon damage points impl Character { ... fn attack(&self, target: &Character) { } } And borrows a player in order to modify its HPs
  • 62.
    impl Character { ... fnattack(&self, target: &Character) { target.hp -= self.weapon.damage; } }
  • 63.
    fn main() { ... display_character_hp(&player); ally.attack(&player); } Plottwist! The ally attacks! impl Character { ... fn attack(&self, target: &Character) { target.hp -= self.weapon.damage; } }
  • 64.
    fn main() { ... display_character_hp(&player); ally.attack(&player); } implCharacter { ... fn attack(&self, target: &Character) { target.hp -= self.weapon.damage; } } error[E0594]: cannot assign to field `target.hp` of immutable binding --> src/main.rs:38:9 | 37 | fn attack(&self, target: &Character) { | ---------- use `&mut Character` here to make mutable 38 | target.hp -= self.weapon.damage; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot mutably borrow field of immutable binding
  • 65.
  • 66.
    Mutable Borrowing (&mutT) You can borrow a mutable reference to a value Borrowing a mutable reference forbids any 
 other access to the value
  • 67.
    fn main() { ... ally.attack(&mutplayer); } impl Character { ... fn attack(&self, target: &mut Character) { target.hp -= self.weapon.damage; } }
  • 68.
    fn main() { ... ally.attack(&mutplayer); } impl Character { ... fn attack(&self, target: &mut Character) { target.hp -= self.weapon.damage; } } Now takes a mutable reference
  • 69.
  • 70.
    • No danglingpointers Was it hard?
  • 71.
    • No danglingpointers • No memory leaks Was it hard?
  • 72.
    • No danglingpointers • No memory leaks • No segfaults Was it hard?
  • 73.
    • No danglingpointers • No memory leaks • No segfaults • No data races Was it hard?
  • 74.
    • No danglingpointers • No memory leaks • No segfaults • No data races • Performance comparable to C++ Was it hard?
  • 75.
    • No danglingpointers • No memory leaks • No segfaults • No data races • Performance comparable to C++ • Basically if it compiles, it will never break Was it hard?
  • 76.
  • 77.
    • Tough learningcurve Cons of Rust (ATM)
  • 78.
    • Tough learningcurve • Lack of libraries Cons of Rust (ATM)
  • 79.
    • Tough learningcurve • Lack of libraries • Poor IDEs support Cons of Rust (ATM)
  • 80.
    • Tough learningcurve • Lack of libraries • Poor IDEs support • Long compile times Cons of Rust (ATM)
  • 81.
    • Tough learningcurve * • Lack of libraries * • Poor IDEs support * • Long compile times * They’re working on it! Cons of Rust (ATM)
  • 82.
  • 83.
    Crates [package] name = "hello_world" version= "0.1.0" authors = ["Giorgio Pomettini <giorgio.pomettini@gmail.com>"] Cargo.toml
  • 84.
    Crates [package] name = "hello_world" version= "0.1.0" authors = ["Giorgio Pomettini <giorgio.pomettini@gmail.com>"] [dependencies] rand = "0.3" Cargo.toml
  • 85.
    Crates [package] name = "hello_world" version= "0.1.0" authors = ["Giorgio Pomettini <giorgio.pomettini@gmail.com>"] [dependencies] rand = "0.3" extern crate rand; use rand::Rng; fn main() { ... let mut ally: Character = Character::new(); ally.weapon = sword; ally.weapon.damage = rand::thread_rng().gen_range(0, 10); } Cargo.toml
  • 86.
  • 87.
    What about theIDE? https://areweideyet.com/ • Syntax Highlighting • Code Completion • Code Formatting • Debugging
  • 88.
    What about theIDE? https://areweideyet.com/ My pick:
 ❤ VS Code + RLS ❤ • Syntax Highlighting • Code Completion • Code Formatting • Debugging
  • 89.
    Who uses Rustin production?
  • 90.
    Who uses Rustin production? Everyday we work with something (partially) built in Rust
  • 91.
    Who uses Rustin production? Everyday we work with something (partially) built in Rust
  • 92.
    Who uses Rustin production? (Gamedev)
  • 93.
    Who uses Rustin production? (Gamedev)
  • 94.
    Who uses Rustin production? (Gamedev) WAIT! Don’t leave the room yet!
  • 95.
    Who uses Rustin production? (Gamedev) “Penso che Rust sia il linguaggio low level più efficace, pratico e divertente. Codice legacy a parte ho finalmente chiuso con C/C++”
  • 96.
    Who uses Rustin production? (Gamedev) Ho un sogno: entro i prossimi dieci anni spero che tutto il nostro codice nativo sarà in Rust […]
  • 97.
    Who uses Rustin production? (Gamedev) “Rustifizzare” le codebase diventerà presto un obbligo di sicurezza per chi fa platform development
  • 98.
  • 99.
    Games written inRust SHAR (WIP, Steam) * A futuristic soccer game with deterministic physics synchronized between clients
  • 100.
    Games written inRust Citybound (WIP) * Like SimCity but with a million people on the screen at the same time, each one with a different routine
  • 101.
    Games written inRust A Snake’s Tale (Steam, App Store, Play Store) * A colorful puzzle game. Runs on every PC and mobile platform
  • 102.
    Games written inRust WitchBrook (WIP, Steam + Console) * From the same authors of Stardew Valley. First pure Rust console game
  • 103.
  • 104.
    Where should Istart? •Rust Book
  • 105.
    Where should Istart? •Rust Book •Into_Rust();
  • 106.
    Where should Istart? •Rust Book •Into_Rust(); •Programming Rust
  • 107.
    Where should Istart? •Rust Book •Into_Rust(); •Programming Rust •#rust-beginners IRC
  • 108.
    Where should Istart? •Rust Book •Into_Rust(); •Programming Rust •#rust-beginners IRC •/r/Rust Reddit
  • 109.
    Where should Istart? •Rust Book •Into_Rust(); •Programming Rust •#rust-beginners IRC •/r/Rust Reddit •Clippy (code linter)
  • 110.
    Where should Istart? http://arewegameyet.com/
  • 111.
    Game Engines Piston GGEZAmethyst Pros Cons
  • 112.
    Game Engines Piston GGEZAmethyst Pros Modular Lot of components Support for 2d and 3d Cons Not beginner friendly
  • 113.
    Game Engines Piston GGEZAmethyst Pros Modular Lot of components Support for 2d and 3d Inspired by Love2D Easy to learn Lightweight Cons Not beginner friendly Few components
  • 114.
    Game Engines Piston GGEZAmethyst Pros Modular Lot of components Support for 2d and 3d Inspired by Love2D Easy to learn Lightweight Data-driven Good for prototyping Support for 2d and 3d Cons Not beginner friendly Few components Poor documentation
  • 115.
    Let’s make anIdle Game!
  • 116.
    Let’s make anIdle Game! // I load GGEZ extern crate ggez; use ggez::{GameResult, Context, ContextBuilder}; use ggez::graphics::{self, DrawMode, Point2, Font, Text}; use ggez::conf; use ggez::event::{self, MouseButton}; struct MainState { font: Font, text: Text, cookies: u32 }
  • 117.
    Let’s make anIdle Game! impl MainState { // Context Init. The context holds the hardware state // GameResult is a value of type Result used for error handling fn new(ctx: &mut Context) -> GameResult<MainState> { // Load the text let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf", 32)?; // Draw the empty text let text = graphics::Text::new(ctx, "", &font)?; let s = MainState { font, text, cookies: 0 }; // If we got no errors I return the state Ok(s) } }
  • 118.
    Let’s make anIdle Game! impl MainState { // Context Init. The context holds the hardware state // GameResult is a value of type Result used for error handling fn new(ctx: &mut Context) -> GameResult<MainState> { // Load the text let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf", 32)?; // Draw the empty text let text = graphics::Text::new(ctx, "", &font)?; let s = MainState { font, text, cookies: 0 }; // If we got no errors I return the state Ok(s) } } In Rust errors are values (Result)
  • 119.
    Let’s make anIdle Game! impl event::EventHandler for MainState { fn update(&mut self, ctx: &mut Context) -> GameResult<()> { // I draw the cookie amount on screen self.text = graphics::Text::new(ctx, &format!("Cookies: {}", self.cookies), &self.font)?; Ok(()) } fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { // I clear the screen graphics::clear(ctx); // I draw the text graphics::draw(ctx, &self.text, Point2::new(250.0, 150.0), 0.0)?; // I draw a pseudo cookie graphics::circle(ctx, DrawMode::Fill, Point2::new(400.0, 400.0), 100.0, 2.0)?; // Blit graphics::present(ctx); Ok(()) } fn mouse_button_down_event(&mut self, _ctx: &mut Context, _button: MouseButton, _x: i32, _y: i32) { // Every time I click the screen I get one cookie self.cookies += 1; } }
  • 120.
    Let’s make anIdle Game! impl event::EventHandler for MainState { fn update(&mut self, ctx: &mut Context) -> GameResult<()> { // I draw the cookie amount on screen self.text = graphics::Text::new(ctx, &format!("Cookies: {}", self.cookies), &self.font)?; Ok(()) } fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { // I clear the screen graphics::clear(ctx); // I draw the text graphics::draw(ctx, &self.text, Point2::new(250.0, 150.0), 0.0)?; // I draw a pseudo cookie graphics::circle(ctx, DrawMode::Fill, Point2::new(400.0, 400.0), 100.0, 2.0)?; // Blit graphics::present(ctx); Ok(()) } fn mouse_button_down_event(&mut self, _ctx: &mut Context, _button: MouseButton, _x: i32, _y: i32) { // Every time I click the screen I get one cookie self.cookies += 1; } } This is a trait. It’s like a C# interface
  • 121.
    Let’s make anIdle Game! pub fn main() { // Context Builder will set up the window let cb = ContextBuilder::new("Cookie Clicker", "Pomettini") .window_setup(conf::WindowSetup::default().title("Cookie Clicker")) .window_mode(conf::WindowMode::default().dimensions(800, 600)); // I initialize the context let ctx = &mut cb.build().unwrap(); // I set MainState as the starting state let state = &mut MainState::new(ctx).unwrap(); // I run the event loop event::run(ctx, state).unwrap(); }
  • 122.
    Let’s make anIdle Game!
  • 123.
    But… is thereUnity for Rust?
  • 124.
    But… is thereUnity for Rust? https://github.com/GodotNativeTools/godot-rust
  • 125.
    Let’s make ourGame Engine!
  • 126.
    Let’s make ourGame Engine! C Bindings Pure Rust
  • 127.
    Let’s make ourGame Engine! C Bindings Pure Rust Window + Input sdl2 glutin (GLFW)
  • 128.
    Let’s make ourGame Engine! C Bindings Pure Rust Window + Input sdl2 glutin (GLFW) Graphics gl-rs (OpenGL) glium
  • 129.
    Let’s make ourGame Engine! C Bindings Pure Rust Window + Input sdl2 glutin (GLFW) Graphics gl-rs (OpenGL) glium Audio alto (OpenAL) rodio
  • 130.
    Let’s make ourGame Engine! C Bindings Pure Rust Window + Input sdl2 glutin (GLFW) Graphics gl-rs (OpenGL) glium Audio alto (OpenAL) rodio Physics nphysics
  • 131.
    Let’s make ourGame Engine! C Bindings Pure Rust Window + Input sdl2 glutin (GLFW) Graphics gl-rs (OpenGL) glium Audio alto (OpenAL) rodio Physics nphysics ezing (Easing), pathfinding (Pathfinding), tiled (Tilemaps)
  • 132.
  • 133.
    Special thanks tothe Rust Roma community and in particular to Enrico Risa
  • 134.
    • Mail: giorgio.pomettini@gmail.com •Sito web: www.videogio.co • Twitter: @dreamquest