Time Travel
for Game Development
with Elm
by @doppioslash
11th of June 2015 - Functional Programming eXchange - London
About me
What I do
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 achieve a 10 moves combo to check if you have fixed an inconvenient bug?
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)
Make a change and test on PC
Example Common Game Development Workflow (starring Unity)
Example Common Game Development Workflow (starring Unity)
All works
Make a change and test on Device
Example Common Game Development Workflow (starring Unity)
Make a change and test on Device
Start build
Make a change and test on Device
20 minutes later
(if your build times are still sane)
Make a change and test on Device
Get the build file, load it on device
Make a change and test on Device
Find new and exciting bugs
Slow Iteration times
Say bye to Flow
Those 45m that took you to load the problem in your brain? Lost.
Slow Iteration times
you forgot what you started a build for
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
If you could have the ideal workflow what would you want it to be like?
(outside of having a magic 'Make game' button)
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 during the entire session
Is that even possible?
Which language makes it all possible RIGHT NOW?
Elm
(I'm sure no one saw this coming)
(Elm debug demo)
What sort of language is Elm?
What sort of language is Elm?
Purely Functional
Functional Reactive
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
Elm Reactor
Elm Reactor
Inspired by Inventing on Principle
Elm Reactor
Also solves the 'debug mouse movements conundrum'
Elm Reactor
Fundamentals made in a few days by Laszlo
Elm Reactor
Because Elm's language design was 'compatible'
Elm Architecture
Elm Architecture
Imports
Elm Architecture
import Graphics.Element exposing (..)
import Time
import Window
Elm Architecture
Model
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
type alias GameState = {}
defaultGame : GameState
defaultGame = {}
Elm Architecture
Display
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
Update
stepGame : Input -> GameState -> GameState
stepGame {timeDelta,userInput} gameState =
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
Main
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
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
apply a function on a signal
returns another, transformed, signal
What kind of functions can we apply on signals?
apply a function on two signals
What kind of functions can we apply on signals?
make a signal that depends on the past values of a signal
foldp : (a -> state -> state) -> state -> Signal a ->
Signal state
What is this foldp thing?
What is this foldp thing?
Fold from the past
What is this foldp thing?
foldp takes (a -> state -> state)
a function
What is this foldp thing?
... -> state -> ...
a default state
What is this foldp thing?
... -> Signal a -> ...
an input signal
What is this foldp thing?
... -> Signal state
returns a signal (next state of the program, after applying update)
What is this foldp thing?
rules out having signals of signals
How Elm Reactor works
Record Inputs
How Elm Reactor works
Reapplies functions to inputs
How Elm Reactor works
combines the previous state and old inputs to make the current state.
How Elm Reactor works
snapshotting for performance
How Elm Reactor works
How Elm Reactor works
changes to types will break hot swapping
if a change doesn't compile
How Elm Reactor works
What about Elm makes it a good fit for a Time Travelling Debugger
Why Elm Reactor works
Applying the same inputs will return the same output
Why Elm Reactor works
No side effects so safe to 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
Roguelike
Castle of Elm
Made in a couple of days
Castle of Elm
From scratch, only with Elm apis
Castle of Elm
Still slightly more than toy game
Castle of Elm
Flexible tile sistem
Castle of Elm
Character collisions
Castle of Elm
Demo
Castle of Elm
Ok, it can't be all good
Out of memory
Ok, it can't be all good
schroedinger hot swapping
Ok, it can't be all good
Ok, it can't be all good
But you can help!
It's OSS
Why it's worth to 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 parallelisations
Time Travel in Game Development with Elm at FPX 2015
By Claudia Doppioslash
Time Travel in Game Development with Elm at FPX 2015
- 3,547