Slide 1

Slide 1 text

Whilst We Wait 1. Get LÖVE https://love2d.org/ 2. Code along git clone https://github.com/quad/invader.love.git

Slide 2

Slide 2 text

Functional Reactivity A Video Game and A Piece of CRUD

Slide 3

Slide 3 text

Reactive Programming a = 1 b = 1 c = a + b print c 2 b = 2 print c

Slide 4

Slide 4 text

Functional Reactive Programming

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Space Invaders git checkout -f WORLD

Slide 7

Slide 7 text

function love.load() w = meta.apply(world) app = gvt.start(w) end main.lua

Slide 8

Slide 8 text

Functional World ‏ 0.6s ‐ 0.2s

Slide 9

Slide 9 text

function love.keypressed(key) if app.state ~= 'ready' then gvt.step(app, 'key.' .. key) end end main.lua

Slide 10

Slide 10 text

Game Loops loop do input update draw wait end

Slide 11

Slide 11 text

function love.update(dt) if app.state ~= 'ready' then gvt.step(app, 'dt', dt) elseif app.state ~= 'stopped' then love.event.push('q') end end main.lua

Slide 12

Slide 12 text

world.lua return function() await(5, 'key.escape') end

Slide 13

Slide 13 text

Demo

Slide 14

Slide 14 text

Event Systems • Main loop • Events • Queue • Dispatcher • Handlers

Slide 15

Slide 15 text

git checkout -f DRAW

Slide 16

Slide 16 text

main.lua screen = {} function love.load() w = meta.apply(world, {Screen=screen}) app = gvt.start(w) end

Slide 17

Slide 17 text

Imperative World ‏ 0.6s ‐ 0.2s Imperative World Screen

Slide 18

Slide 18 text

world.lua thing = {} function thing:_draw_list() return {{'rectangle', 'line', 10, 10, 500, 500}} end __.extend(Screen, {thing}) await('key.escape')

Slide 19

Slide 19 text

main.lua function love.draw() __(screen):chain() :map(function(o) return o:_draw_list() end) :concat() :each(function(d) love.graphics[d[1]](unpack(d, 2)) end) end

Slide 20

Slide 20 text

Demo

Slide 21

Slide 21 text

Time Check Is this boring?

Slide 22

Slide 22 text

git checkout -f BULLET

Slide 23

Slide 23 text

world.lua bullet = Bullet(500, 500, Consts.bullet.v) __.extend(Screen, {bullet})

Slide 24

Slide 24 text

bullet.lua function draw_list(x, y) return { {'setLineWidth', Consts.bullet.width}, {'line', x, y, x, y + Consts.bullet.height}, {'setLineWidth', 1}, } end

Slide 25

Slide 25 text

bullet.lua return { _draw_list = L(draw_list)(_x, _y), }

Slide 26

Slide 26 text

“Lift” • draw_list is a pure function • Same input, same output • _draw_list is a “lifted” function • Changed input, changed output

Slide 27

Slide 27 text

bullet.lua function constructor(ix, iy, v) _x = ix _y = iy + S(v)

Slide 28

Slide 28 text

That’s S(v) as in ∫v O H SN AP C ALC U LU S

Slide 29

Slide 29 text

Demo

Slide 30

Slide 30 text

Chain Reactions Bullet dt S(v) _y _draw_list _x

Slide 31

Slide 31 text

git checkout -f SWARM

Slide 32

Slide 32 text

world.lua swarm = Swarm(Consts.swarm.initial.x, Consts.swarm.initial.y) __.extend(Screen, {bullet, swarm})

Slide 33

Slide 33 text

swarm.lua function constructor(ix, iy) ... _v = Consts.swarm.speed _x = ix + S(_v) _y = iy

Slide 34

Slide 34 text

swarm.lua invaders = __.range(1, Consts.swarm.number) :map(function(n) return Invader(n - 1, _x, _y) end)

Slide 35

Slide 35 text

invader.lua function constructor(n, sx, sy) ... col = n % Consts.swarm.columns row = math.floor(n / Consts.swarm.columns) _x = (col * (Consts.invader.side * Consts.invader.spacing.x)) + sx _y = (row * (Consts.invader.side * Consts.invader.spacing.y)) + sy

Slide 36

Slide 36 text

invader.lua function draw_list(x, y) return {{ 'rectangle', 'line', x, y, Consts.invader.side, Consts.invader.side, }} end

Slide 37

Slide 37 text

swarm.lua function draw_list(invaders, x, y) return __(invaders):chain() :map(function(i) return i:_draw_list() end) :concat() :value() end

Slide 38

Slide 38 text

Demo

Slide 39

Slide 39 text

Chain Reactions Swarm Invader dt S(v) _x _draw_list _x _y _y _draw_list

Slide 40

Slide 40 text

git checkout -f BOUNCE

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

invader.lua function bounced(x) return x <= 0 or (x + Consts.invader.side) >= Consts.screen.width end return { _draw_list=L(draw_list)(_x, _y), _bounced=L(bounced)(_x), }

Slide 43

Slide 43 text

swarm.lua _bounced = __.reduce( invaders, false, function(c, i) return OR(c, i._bounced) end )

Slide 44

Slide 44 text

swarm.lua function bounce() _v = _v() * -1 _y = _y() + Consts.invader.close end link(cond(_bounced), bounce)

Slide 45

Slide 45 text

Demo

Slide 46

Slide 46 text

• Imperative exception to Functional graph traversal • Acts like a fork • “Reacts” to other Reactors • All reactive variables are Reactors The Reactor

Slide 47

Slide 47 text

git checkout -f PLAYER

Slide 48

Slide 48 text

world.lua player = Player(Consts.player.initial.x, Consts.player.initial.y)

Slide 49

Slide 49 text

player.lua function constructor(ix, iy) ... _x = ix _y = iy return { _draw_list = L(draw_list)(_x, _y), }

Slide 50

Slide 50 text

player.lua function draw_list(x, y) return {{ 'triangle', 'line', x, y, x + Consts.player.width, y + Consts.player.height, x - Consts.player.width, y + Consts.player.height, }} end

Slide 51

Slide 51 text

Demo

Slide 52

Slide 52 text

git checkout -f MOVE

Slide 53

Slide 53 text

world.lua link('key.left', player.left) link('key.right', player.right)

Slide 54

Slide 54 text

player.lua return { _draw_list = L(draw_list)(_x, _y), left = move(-1), right = move(1), }

Slide 55

Slide 55 text

player.lua function move(d) return function() _dir = d end end

Slide 56

Slide 56 text

player.lua _dir = 0 _x = ix _y = iy _v = L(v)(_dir, delay(_x)) _x = ix + S(_v)

Slide 57

Slide 57 text

Delayed Evaluation _dir v _v _x _int_v

Slide 58

Slide 58 text

Delayed Evaluation _dir v _v _x _int_v

Slide 59

Slide 59 text

player.lua function v(dir, x) if x then ... else return 0 end end

Slide 60

Slide 60 text

player.lua if x then if (x <= C.player.width and dir < 0) or (x >= C.screen.width - C.player.width and dir > 0) then return 0 else return Consts.player.speed * dir end end

Slide 61

Slide 61 text

Demo

Slide 62

Slide 62 text

git checkout -f SHOOT

Slide 63

Slide 63 text

world.lua bullet = Bullet(500, 500, C.bullet.v) function shoot() bullet.shoot( player._x(), player._y() - C.bullet.height / 2 ) end link('key. ', shoot) link('key.up', shoot)

Slide 64

Slide 64 text

bullet.lua function shoot(x, y) _x = x _y = y + S(v) end return { _draw_list = L(draw_list)(_x, _y), shoot = shoot, }

Slide 65

Slide 65 text

Demo

Slide 66

Slide 66 text

git checkout -f KILL

Slide 67

Slide 67 text

Collision Detection • In pure implementions, handled “outside” as collision events. • In our hybrid, handled as a reactive state.

Slide 68

Slide 68 text

world.lua swarm = Swarm(C.swarm.initial.x, C.swarm.initial.y, bullet)

Slide 69

Slide 69 text

swarm.lua local function constructor(ix, iy, bullet) ... return Invader(n - 1, _x, _y, bullet)

Slide 70

Slide 70 text

invader.lua _box = L(box)(_x, _y) _hit = L(colliding)(_box, bullet._box) _alive = true

Slide 71

Slide 71 text

invader.lua function box(x, y) return {x=x, y=y, width=Consts.invader.side, height=Consts.invader.side} end

Slide 72

Slide 72 text

invader.lua function colliding(abox, bbox) ax2, ay2 = abox.x + abox.width, abox.y + abox.height bx2, by2 = bbox.x + bbox.width, bbox.y + bbox.height return abox.x < bx2 and ax2 > bbox.x and abox.y < by2 and ay2 > bbox.y end

Slide 73

Slide 73 text

invader.lua function die() _alive = false end link(cond(_hit), die)

Slide 74

Slide 74 text

invader.lua function draw_list(alive, x, y) if alive then ... else return {} end function bounced(alive, x) if alive then ... else return false end

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

Reactivity Huh! Good God! What is it good for?

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

No content

Slide 79

Slide 79 text

•Model - View - Controller •Browser ⁶ Server •Workflows

Slide 80

Slide 80 text

Workflow?! complete := seen [ submission review confirmation ]

Slide 81

Slide 81 text

Event Sourcing Martin Fowler’s

Slide 82

Slide 82 text

most productivity apps editors not useful? relational databases backup/restore filesystems (snapshot) git Redo Undo Event Based Event Based State Based State Based

Slide 83

Slide 83 text

Bullet Swarm Invader Player key.left player_left player_move key.right player_right player_x shoot player_v player_draw_list bullet_shoot player_y bullet_y bullet_x key. key.up bullet_int_v bullet_box bullet_draw_list invader_hit screen swarm_int_v swarm_x swarm_draw_list invader_x invader_bounced swarm_bounced swarm_bounce swarm_v swarm_y invader_y invader_draw_list invader_box invader_die invader_alive player_dir player_int_v dt

Slide 84

Slide 84 text

•Reactive Programming > ˎ •People demand interactivity •Fork and Fix Space Invaders

Slide 85

Slide 85 text

fin

Slide 86

Slide 86 text

LuaGravity

Slide 87

Slide 87 text

Push-pull functional reactive programming http://conal.net/papers/push-pull-frp/

Slide 88

Slide 88 text

The Fran Tutorial http://conal.net/fran/tutorial.htm