We start off by creating the ship. It is controlled by the left and right arrow keys and moves
on the periphery of an imaginary circle. The keyboard is abstracted by the keyboard-extra library
which provides a model that holds the current state of the keyboard.
We first set up the model for the Game, which contains the Player with the Player’s position
(represented by an angle), the current direction in which the player is moving, and a keyboardModel:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="1:25", language="elm" %}{% endcodesnippet %}
Elm 0.17 does not use Signals anymore. Instead we use a publication/subscription pattern that uses messages. We need to declare the type of the message here, which can be one of the following:
-
a
Stepwith a timestamp. This represents a frame of the game-loop. -
a
KeyboardExtraMsgwhich is a keyboard input
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="26:30", language="elm" %}{% endcodesnippet %}
We are also going to need some constant values, e.g. the screen size and the radius of the player’s periphery:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="30:44", language="elm" %}{% endcodesnippet %}
We now define how the state of the game can change over time. This state-transition is done with the function update : Msg → Game → Game. This function will receive our Msg and will update the game state accordingly. We distinguish here between KeyboardExtraMsg and Step:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="99:105", language="elm" %}{% endcodesnippet %}
onUserInput will set the current direction based on the arrow-keys pressed on the keyboard:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="72:87", language="elm" %}{% endcodesnippet %}
onFrame on the other hand will update the game’s state on the next frame.
There is currently only one nextCmd value which does nothing. We are going to add
more commands later on.
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="88:97", language="elm" %}{% endcodesnippet %}
updatePlayer will update the player’s angle depending on the direction of the Input:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="64:70", language="elm" %}{% endcodesnippet %}
Elm provides different libraries to output html or to render 2d-graphics on a canvas. We use the Graphics-Package for this.
The Player will be a small triangle that we rotate around the center of the game.
A black background will represent our game screen. We also change the player’s color depending on the angle (for fun and profit):
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="109:122" %}{% endcodesnippet %}
The function view : Game → Html.Html Msg is the main function of the view part of our application.
It receives the current game state and returns Html:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="123:135" %}{% endcodesnippet %}
With the Model, the Update-function and the View in place we are now able to wire everything together.
For this we need to construct a subscriptions. But let’s take a look at the main-function first
(main is the starting point for every elm-application):
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="161:167", language="elm" %}{% endcodesnippet %}
You’ll notice that besides a subscriptions-function we also need an init function that defines the initial state of our application:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="148:159", language="elm" %}{% endcodesnippet %}
Finally the subscriptions-function will subscribe to keyboard-events and AnimationFrame-events:
{% codesnippet "https://raw.githubusercontent.com/macrozone/elm-hexagon-tutorial/chapter/controls/src/Hexagon.elm", lines="138:144", language="elm" %}{% endcodesnippet %}
Simply start elm-reactor in your project directory, open your browser at http://0.0.0.0:8000/ and navigate to your source file.
You should see your small ship and should be able to control it with the arrow-keys ← and →.