16 Jun 2013 Using EaselJS to create a simple arcade game, part II: The Shapes.

This is the second part of a series about using EaselJS to create a simple HTML5/js based arcade game.

In this part, we'll learn about:

  • doing multiple animations at the same time,
  • drawing diferent shapes,
  • containers.

In the first part, we left with just a moving plate. It's time to give it a ball now.

Thankfully, Graphics object has just the method for this: drawCircle. This time we're gonna pack our ball into a class - deriving from createjs.Shape - from the very beginning.

But before that, let's prepare some ground for supporting multiple objects at the same time.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Main
    constructor: (name) ->
        @canvas = document.getElementById name
        @plate = new Plate @canvas
        @ball = new Ball @canvas
        document.onkeydown = @handleKeyDown
        document.onkeyup = @handleKeyUp

    init: ->
        @plate.init()
        @ball.init()
        @stage = new createjs.Stage @canvas
        @stage.addChild @plate
        @stage.addChild @ball
        createjs.Ticker.useRAF = yes
        createjs.Ticker.setFPS 60
        createjs.Ticker.addListener @

    tick: ->
        @plate.tick()
        @stage.update()

window.main = new Main "main"
window.main.init()

Nothing fancy here. The Plate object is a slightly refactored version of the one from previous part of this tutorial. With key handlers we'll deal later, now let's focus on the Ball.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Ball extends createjs.Shape
    constructor: (@canvas) ->
        super()
        @graphics.beginFill("#6b0000").drawCircle 0, 0, 5
        @maxwidth = @canvas.width
        @maxheight = @canvas.height - 10

    init: ->
        @x = @maxwidth / 2
        @y = @maxheight - 5

no canvas, sorry
start reset raw

Alright, so the ball is in place. Oh, wait, in place?! It should move along with the plate, shouldn't it? Of course, we need to tie them together. Let's move to the key handlers now.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Ball
    #(...)
    constructor: (@canvas) ->
        #(...)
        @ddx = [0, 0]

    tick: ->
        @x += @ddx[0] + @ddx[1]

    setLeft: (dx) ->
        @ddx[0] = dx

    setRight: (dx) ->
        @ddx[1] = dx


class Main
    #(...)
    handleKeyDown: (e) =>
        if !e
            e = window.event
        switch e.keyCode
            when KEY_LEFT
                @plate.setLeft -1
                @ball.setLeft -1
            when KEY_RIGHT
                @plate.setRight 1
                @ball.setRight 1

    handleKeyUp: (e) =>
        if !e
            e = window.event
        switch e.keyCode
            when KEY_LEFT
                @plate.setLeft 0
                @ball.setLeft 0
            when KEY_RIGHT
                @plate.setRight 0
                @ball.setRight 0

We are using the same trick here as we did for the Plate, because it suffers from the same problem. You can see that we are catching and resolving key events in the Main class. I'm still not sure if it's the best approach, but it will do for now.

no canvas, sorry
start reset raw

Better. Now let's create some blocks meant to be destroyed by our Ball. Normally, I'd just place some rectangles there at random positions, but since we want to learn how to draw different things in EaselJS, we'll do something more fancy. How about this.

no canvas, sorry
start reset raw

I'm not going to dive into the details here (you can check the raw source if you want to). Instead, let's focus on different shapes. Rectangles are easy, right? What about this rounded rectangle on the top? There is a drawRoundRectComplex method in the Graphics class, just for that. It is Complex, because it let's you specify radius independently for every corner, in opposite to drawRoundRect which sets the same radius for all of them. To conclude the easy part, there are drawEllipse and drawCircle methods for ellipses and circles, respectively.

Now, the tasty part. To draw shapes which are not available out of the box, we'll use a concept of paths. Path is basically a collection of lines where every line has a common point with at least one other line. Note that those lines do not need to be straight, they can be some kind of curve as well. When we take a closed path (which begins and ends in the same point), they will form a figure.

It is probably better to be seen as picture(s). We'll start with triangles, they're quite obviously easier ones.

easeljs2_1

We are using lineTo function here to create straight lines. It's equivalent for curves are curveTo and bezierCurveTo. Actually, they are both Bezier, former being quadratic and latter being cubic.

Let's see a picture again here.

easeljs2_2

To find out more about Bezier curves, check out wikipedia article. It has necessary explanations, formulas and even animated gifs showing how it works.

To conclude this part, a few words about containers. We've seen them before: Our Stage is in fact the main container, where everything else lives. But we can create more containers and they can behave like Graphics objects and be used to group other Graphics objects. We can then manipulate multiple objects at once. Note however that, while useful, it should not be overused, because containers produce additional overhead which may cause your application to become slow.