Time Travel
for Game Development
with Elm
by @doppioslash
20th of November 2015 - Codemotion - Milan
About me
Game Developer &
Functional Programmer
Table of Contents
- GameDev workflow = hell
- Time Travelling Debugger?
- Meet Elm
- Structuring programs in Elm
- Time Travelling Demo
- Gotchas
What is the single most soul destroying thing in game development?
What is the single most soul destroying thing in game development?
C++?
What is the single most soul destroying thing in game development?
Having to redo a 10 moves combo every time you check if the bug is gone?
What is the single most soul destroying thing in game development?
Projects getting canned?
Slow Iteration times
What is the single most soul destroying thing in game development?
Example Common Game Development Workflow
(starring Unity)
1. Write some code
Example Common
Game Development Workflow
2. Playtest it
(in the Unity Editor)
Example Common
Game Development Workflow
Now to test that same change on mobile devices:
Example Common Game Development Workflow (starring Unity)
Make a change and test on Device
1. Start build
Make a change and test on Device
3. load the ipa/apk on device
Make a change and test on Device
4. playtest until your code runs
Make a change and test on Device
5. Find new and exciting bugs
(only on device)
Slow Iteration times
Say bye to Flow
Slow Iteration times
Error prone forest of build settings
Slow Iteration times
Deadline panic 10x increase
(suffering together at late hours might be team-building but surely we don't need this :P)
What can fix this?
What can help?
Jenkins churning builds out in background
What can help?
Type system to catch bugs before running
What can help?
Unit testing
What is the ideal workflow?
Inventing
on
Principle
As seen on LambdaCat:
Inventing on Principle
Hot reload: reload changes to the code without stopping the game
Inventing on Principle
Time Travel:
being able to scrub to any point in the session
Inventing on Principle
Omniscience:
see all the state in the session
Is that even possible?
Racket,VR and John Carmack (watch it)
John Carmack
John Carmack
LISP (Racket)
Which language makes it all possible RIGHT NOW?
Elm
(I'm sure no one saw this coming)
(debug.elm-lang.org
Mario demo)
What sort of language is Elm?
What sort of language is Elm?
Purely Functional
Functional Reactive
(FRP)
What sort of language is Elm?
Eager
What sort of language is Elm?
Static Type System
What sort of language is Elm?
Compiles to Javascript, HTML, CSS
What sort of language is Elm?
Interoperates with Javascript while still being type safe
What sort of language is Elm?
Small
What sort of language is Elm?
Invented by Evan Czaplicki for his thesis
What sort of language is Elm?
Meant to be approachable and practical
What sort of language is Elm?
Meant to be approachable and practical
No 'scary' terms like Monad
In Production at
Elm Reactor
(the Time Travelling Debugger)
Elm Reactor
Inspired by Inventing on Principle
Elm Reactor
Fundamentals made in a few days by Laszlo
Elm Reactor
Elm's language design is accidentally 'compatible'
Elm Reactor
You can "step through" while moving the mouse
How do you structure programs in Elm?
The Functional Triforce
Maybe
Union Types
Pattern Matching
The Functional Triforce
Union Types
define the Model:
type Tile
= Door Size
| Column
| BackGround BackGroundTile
| Shadow ShadowTile
The Functional Triforce
Maybe
gets rid of NULL errors
type Maybe a
= Just a
| Nothing
The Functional Triforce
Pattern Matching
String.toInt : String -> Maybe Int
toMonth : String -> Maybe Int toMonth rawString =
case String.toInt rawString of
Nothing ->
Nothing
Just n ->
if n > 0 && n <= 12 then Just n else Nothing
Elm Architecture
Elm is opinionated
Elm Architecture
Use the
"Elm Architecture"
Elm Architecture
Model
View
Update
Overview
Elm Architecture
Model =
the Data Structure we pass around
Model
type alias UserInput = {}
userInput : Signal UserInput
userInput = Signal.constant {}
type alias Input =
{ timeDelta : Float
, userInput : UserInput
}
Model
type alias UserInput = {}
userInput : Signal UserInput
userInput = Signal.constant {}
type alias Input =
{ timeDelta : Float
, userInput : UserInput
}
Type signature
Model
type alias UserInput = {}
userInput : Signal UserInput
userInput = Signal.constant {}
type alias Input =
{ timeDelta : Float
, userInput : UserInput
}
A record
Type alias
Signal
Model
Record =
set of key value pairs
Model
Type alias =
give name to a set of fields in a record
Model
Signal =
updates every time variable changes
Model
type alias GameState = {}
defaultGame : GameState
defaultGame = {}
Elm Architecture
View =
the code that renders from the Model
Display
display : (Int,Int) -> GameState -> Element
display (w,h) gameState = show gameState
Display
display : (Int,Int) -> GameState -> Element
display (w,h) gameState = show gameState
Type signature
Elm Architecture
Update =
the function that does the change of state
Update
stepGame : Input -> GameState -> GameState
stepGame {timeDelta,userInput} gameState =
gameState
Update
stepGame uses the current Input
(which is UserInput and a timeDelta)
to make a new GameState
Elm Architecture
Signals
Signals
delta : Signal Float
delta = Time.fps 30
input : Signal Input
input = Signal.sampleOn delta
(Signal.map2 Input delta userInput)
sampleOn
Signals
delta : Signal Float
delta = Time.fps 30
input : Signal Input
input = Signal.sampleOn delta
(Signal.map2 Input delta userInput)
map2
Signals
gameState : Signal GameState
gameState = Signal.foldp stepGame
defaultGame input
Signals
gameState : Signal GameState
gameState = Signal.foldp stepGame
defaultGame input
foldp
Signals
Signal.map2 =
applies a function that takes 2 arguments
to a signal
Signals
Signal.sampleOn = samples from 2nd input anytime an event occurs in the 1st
Signals
Signal.foldp =
a signal dependent on the past
Main
(where you wire everything up)
Elm Architecture
Main
main : Signal Element
main = Signal.map2 display
Window.dimensions gameState
Main
main : Signal Element
main = Signal.map2 display
Window.dimensions gameState
Signal of Element values
Overview (again)
What are Signals?
Stream of values
What are Signals?
What are Signals?
What are Signals?
a different way of thinking about variables
What are Signals?
an explicit model of variable mutation in time
What are Signals?
non-awkward way of structuring callbacks
What are Signals?
they are wired in signal graphs
(directed acyclic graphs)
What are Signals?
What kind of functions can we apply on signals?
What kind of functions can we apply on signals?
merge : Signal a ->
Signal a -> Signal a
What kind of functions can we apply on signals?
What kind of functions can we apply on signals?
map : (a -> result) -> Signal a -> Signal result
applies a function on a signal
returns another, transformed, signal
What kind of functions can we apply on signals?
applies a function on two signals
What kind of functions can we apply on signals?
makes a signal that depends on the past values of a signal
foldp : (a -> state -> state) -> state -> Signal a ->
Signal state
What is a foldp?
Fold from the past
Fold from the past
Fold from the past
What is a foldp?
foldp takes (a -> state -> state)
a function
What is a foldp?
... -> state -> ...
a default state
What is a foldp?
... -> Signal a -> ...
an input signal
What is this foldp thing?
... -> Signal state
returns a signal
(= next state of the program, after applying update)
How Elm Reactor works
Record Inputs
How Elm Reactor works
Reapplies functions to inputs
How Elm Reactor works
previous state
+
previous inputs =
next state
How Elm Reactor works
snapshotting for performance
How Elm Reactor works
How Elm Reactor works
changes to types will break hot swapping
also if a change doesn't compile
How Elm Reactor works
Why is Elm good for Time Travelling?
Why Elm Reactor works
Applying the same inputs will return the same output
(referential transparency)
Why Elm Reactor works
No side effects =
can replay code
Why Elm Reactor works
All mutable state is stored in the foldp
Static signal graph
Why Elm Reactor works
But, can it scale?
Castle of Elm
But, can it scale?
Game Jam game
Castle of Elm
Somewhat Roguelike
In 2 days
From scratch
Flexible tile system
Castle of Elm
Collisions
(let's break the collisions system)
Castle of Elm
Gotchas
Out of memory
Gotchas
Schroedinger Hot Swapping
Gotchas
But you can help!
It's OSS
<- CODE HERE
Why use statically typed pure Functional languages in Game Development?
Why it's worth to use new language research in Game Development
No runtime exceptions
Why it's worth to use new language research in Game Development
No race conditions
Why it's worth to use new language research in Game Development
Better tools
Why it's worth to use new language research in Game Development
Less code
Why it's worth to use new language research in Game Development
Ease of parallelisation
elm-lang.org/docs
@elmlang
#elmlang
Where to learn Elm?
#haskell.it @ freenode
haskell-ita.it
@Haskell_ITA
Maybe join Haskell ITA
lambdacat.com
@lambda_cat
Read LambdaCat!
Time Travel in Game Development with Elm at Codemotion Milan 2015
By Claudia Doppioslash
Time Travel in Game Development with Elm at Codemotion Milan 2015
- 4,174