Skip to content

Latest commit

 

History

History
165 lines (131 loc) · 4.21 KB

2. Model + View.md

File metadata and controls

165 lines (131 loc) · 4.21 KB

2. Model + View

The next step is to render our game on the screen. In order to do this we first need to model the state of our application.

Our application state

Let's start by defining some values for our board size:

boardWidth =
    500

boardHeight =
    300

We can model our ball as a record type and create a type alias for it. Our ball need some x and y coordinates, as well as a velocity vx and vy. We're also going to store the radius of the ball so it's easier to tweak later on.

type alias Ball =
    { x : Float
    , y : Float
    , vx : Float
    , vy : Float
    , radius : Float
    }

We also need to define a model for our paddles. This model is pretty similar to our Ball except we replace the radius property with width and height:

type alias Paddle =
    { x : Float
    , y : Float
    , vx : Float
    , vy : Float
    , width : Float
    , height : Float
    }

We could also reuse this code by using structural typing [..]

Our application model now needs to contain a Ball and the two paddles:

type alias Model =
    { ball : Ball
    , paddleLeft : Paddle
    , paddleRight : Paddle
    }

Now that we have our model structure, we need to define our initial model state. To break things apart, we can define separate init functions for each of our type aliases.

Let's define start out with a ball that is place in the middle of our board:

initBall : Ball
initBall =
    { x = boardWidth / 2
    , y = boardHeight / 2
    , vx = 0.3
    , vy = 0.3
    , radius = 8
    }

We also need to initialize two separate models for our paddles. It's only the x position is different between the two paddles, so we can create a function that takes in a x value and returns the initial paddle model:

initPaddle : Float -> Paddle
initPaddle x =
    { x = x
    , y = 0
    , vx = 0.4
    , vy = 0.4
    , width = 5
    , height = 80
    }

Our init function that we defined previously can now use these functions to return the initial application state:

init : Model
init =
	{ ball = initBall
	, paddleLeft = initPaddle 20
	, paddleRight = initPaddle (boardWidth - 25)
	}

Here we pass in the x value for our paddles so that they are positioned 20px away from each side.

Views

Now that we have our models it's time to start rendering something to the screen. We're going to use SVG to render our game, so the first thing we need to do is install the elm-lang/svg library. This library allows us to define SVG objects using plain Elm functions, just like our HTML.

Let's start by installing the svg package:

elm package install elm-lang/svg

And import the package at the top of your file:

import Svg exposing (..)
import Svg.Attributes exposing (..)

Now that we have the SVG library, we can define a function to render our ball view. The elm-lang/svg exposes a bunch of functions, in this case a function called circle, that takes a list of attributes and a list of child nodes. We can use this to render a circle positioned based on our Ball state:

ballView : Ball -> Svg Msg
ballView model =
    circle
        [ cx (toString model.x)
        , cy (toString model.y)
        , r (toString model.radius)
        , fill "white"
        ]
        []

And we can do the same for the paddles:

paddleView : Paddle -> Svg Msg
paddleView model =
    rect
        [ width (toString model.width)
        , height (toString model.height)
        , x (toString model.x)
        , y (toString model.y)
        , fill "white"
        ]
        []

It's now time to update the view function we define earlier. We need to render a svg element that contain our ball and the paddles:

view : Model -> Html Msg
view model =
    svg
        [ width (toString boardWidth)
        , height (toString boardHeight)
        ]
        [ rect
            [ width (toString boardWidth)
            , height (toString boardHeight)
            , fill "black"
            ]
            []
        , ballView model.ball
        , paddleView model.paddleLeft
        , paddleView model.paddleRight
        ]

If you hit refresh your browser, you should see something that looks very much like a Pong game.

Next up: making things move!