I believe it’s high time we attempted to build a game with the engine we have so far; wouldn’t you agree? We’ll be making Asteroids, which first made its debut in November 1979; released by Atari Inc.
There are so many ways we could implement the game:
- we could use sprite sheets, as we do support them now
- we could use code to draw the game elements
- we can even add sounds as the AssetsLoader class supports this
I believe there’s more learning value in trying to draw the game elements using JavaScript, so things like: the player, bullets, asteroid and star fields will all be individual classes.
We don’t have fancy things like collision yet, so the game will be pretty dull at first, but don’t worry… collision is definitely on the to-do-list.
We’ll start with the player… we’ll need some sort of ship, that moves according to the VerletModel we previously implemented. The canvas cartesian coordinate system begins with x = 0 and y = 0 at the top-left corner, so anything we draw is relative to that; we want this ship:
The instructions necessary to draw this are: moveTo() point A then lineTo() points B, C, D and back to A. The line from D to A is optional, as we could simply call closePath(). We’ll reuse points B, C and D, with some offsets, to create the ship thruster.
We could create a utility method for drawing. It would take two parameters: a set of actions and a set of coordinates for each action. This method should be part of the DisplayObject class as anything that’s drawn, extends it.
We’re only using moveTo() and lineTo() for now, so that’s all our engine will be instructed to use:
The draw() method can be used like this:
// normal approach
// moveTo(10, 10)
// lineTo(10, 20)
// lineTo(20, 20)// draw method approach
draw([0, 1, 1], [[10, 10], [10, 20], [20, 20]]);
You could argue this method does more harm than good and without proper documentation I admit, it can be confusing… but it’s a helper method, we don’t have to use it. For the sake of clarity, I won’t be using it in these posts.
Our ship needs to rotate around its center point so that fact has to be taken into account when we calculate the coordinates needed to draw it.
As you can see, our Player class is both a view and a controller. You can control the ship using the arrow keys or (W, A, D), and the SPACE key to play a shooting sound (although we’re don’t have bullets yet). We’re missing the PlayerModel… let’s add that as well:
This one is similar to what we’ve implemented in our previous examples, but with a few extra features. The update function of the PlayerModel also treats rotation and adds a speed trap which slows down the ship if the thrusters are off. We could add all of these features directly into the VerletModel and just enable them if/when we need them, but this is fine for now.
The next thing we could do is create a Map class. This would draw some indicators of all the objects rendered on the scene, like the player and asteroids.
It’s basically an in-game map and it will take two parameters:
- the marker (indicator) size and
- the map scale factor.
The latter will represent the percentage of the map size, relative to the scene size. The Map class looks like this:
The getSize() method will resize the marker when it gets close to the outer edges of the map. This is to prevent it from overflowing the Map container size.
Let’s also add in a StarField for good measure; it should generate:
- a dynamic number of stars
- it would be nice to automatically generate 3 types of star sizes (large, medium, small) to emulate some sort of depth; we’ll also change their colors from bright white to dark gray.
- it should move the stars relative to the PlayerModel and star size, creating a parallax effect where closer stars move faster than stars further away
You’ll notice that we’re calling super.update() in the update() method. That’s to make sure that all of the stars that we added as children in the generateStars() method, are rendered. Alternatively we could write our own render() method that does this, but let’s use the engine :D!
The parallax effect comes into play on lines 62 & 63 where we’re calculating the x and y positions of each star based on the model velocity and star scale. We’re also wrapping the stars to the scene, so it feels like we’re flying through a never ending field. Changing the star color based on its size also adds a nice touch to the overall effect.
You’ll also notice we’re using a Particle class in there. That’s something new and it’s part of the engine. It draws a circle of a specified radius and color:
Let’s put everything together and see how it works:
The Demo (no sounds in free codepen account):
Source code:
Next time we’ll learn how to generate random asteroids, so that all of the rocks look a bit different, add them to the map for tracking and bullet generation logic.