Elm: v0.14 Last updated: 03 Mar, 2015
This is the second primer article in the series “Developing Games in Elm” in which I discuss the two main fundamental differences between elm and more traditional programming languages. If you haven’t read the previous article yet I recommend you do that first.
Elm is not just a functional language, it is a functional reactive language. It gives your game the ability to react to signals from the outside world; to player inputs and time.
In game development one of the most important concepts is the event. An event represents a thing that happened during the cycle of the game loop, for example mouse movement. The various modules in the code can attach a listener to the ‘mouse move’ event so that when it is triggered the listener function is run to modify some object(s).
This is by it’s very nature a side effect, which as you’ll remember from the previous article is a bad idea.
Instead we want to be able to react to events in a pure functional way. We can do this with elm’s signals.
A signal is a value that changes over time. The simplest example is time itself. Let’s say we have a signal of milliseconds that updates every second:
Since the value of the signal only changes each second, if we sample it multiple times within the same second we will get the same value back. The value isn’t fired to us in a listener when it changes, instead we sample it from the signal.
Now we need a way to use this signal, since we can’t listen to it and change some other object directly we have to map it into the game’s state and handle the value from there.
As is common, elm uses the
main function as it’s entry point. This function should return an element which can be rendered:
But that is just static content, if we want dynamic content we output a signal of elements:
The value of the signal is mapped to the
Text.asText function which passes it as a string into an element.
But we don’t typically want to just blindly get the time since 1970. When making a game you need to get the exact delta since the last frame to ensure you can scale your time based calculations appropriately. This scaling prevents your game logic running at erratic speeds if your fps varies.
This is nice and simple in in elm, here we just output the delta every frame at a target of 60 frames per second:
As well as time, we can get inputs from the player. Continuing with our mouse move example; instead of listening for mouse move events, with elm we map the
Mouse.position to our game logic:
Few games only take one input, so we can merge a second or more signals together.
If multiple signals change at the same time priority is given to the left most signal. In the following example if the mouse is moving at the same time as it is clicked the
position signal is given priority over
Now we have access to various input signals we want to apply these to our game state over time. Elm has this wonderful concept of folding over the past.
This takes a function which transforms the state with the value of the input signal and then outputs a signal with the new value of the state.
In this example we get the maximum position the mouse has been moved to, i.e. how far to the bottom right of the window.
We are now able to communicate with the outside world, but what about communications between different parts of our game internally? For this we can use custom channels. A channel is what a signal is sent on and can be subscribed to by another piece of the game to receive updates to the value. All the in-built examples we’ve seen so far are channels.
To send our own signals we create a channel that can receive values of a set type and takes a default value. To get the signal from this channel we subscribe to it and can then handle it as before.
So we’ve now looked into the two most important differences between traditional languages and elm. Functional programming provides a more descriptive way to write code, and signals allow your game to react to time and inputs.
The next article in this series will delve into architecting a space invaders clone. With multiple modules, inputs, graphics and aliens it will demonstrate a successful approach to creating games in elm.
Updated [02 Mar, 2015]: Added a lead note indicating using elm v0.14. Updated [05 Mar, 2015]: Added a section on custom channels.