Let’s build an HTML5 game! (Beginner Tutorial, Part 3)

Let’s build an HTML5 game! (Beginner Tutorial, Part 3)

We are almost finished making our first HTML5 game! All we need now is to keep score and keep the action going. Keeping score is fairly simple. A global counter works very well for this type of game. Keeping things moving continuously, however, will take a bit more thought.

The Infinite in Infinite Runner

So, let’s recap our original game idea:

The game I have in mind is a hybrid tower defense/infinite runner type game. Enemies constantly come at you from the top of the game screen and you have to put defense obstacles in their path to defeat them.

  • Enemies coming down from the top of the screen: Check.
  • Defense tower to kill the enemies: Check.
  • Infinite: Todo.

We’re going to take a simple approach here, K.I.S.S. style. Our enemies will be sent down the screen in waves. New Defense Towers will be awarded based on the number of kills. Towers hit by an enemy will destroy both. Once we accomplish these objectives we can discuss refactoring to create different play styles.

Using The Javascript Console

As this is a beginner tutorial, I will assume some readers are not familiar with the javascript console on your browser. Now is a good time to introduce that while we create some reusable functions. Our first function will be a addNewDefense method to handle adding new towers when the player hits the appropriate level of enemy kills.

If you didn’t save your work from Part 1 or Part 2, you can pick up from this JS Bin save. I will still be using Codio to complete the game.

First let’s create a global settings object. If we just create a bunch of variables at the top of our javascript file, we will be polluting the global namespace. In otherwords, if we write var x = 10; that is equal to writing window.x = 10; Every variable that is not in a function will end up in the global ( window.) namespace which means other plugins or code that might use the same variable in a non-encapsulated manner will cause conflicts. I like to create a global Settings object to store all my variables and settings related data.

At the top of our javascript file main.js, write the following:

We will use these variables as the values for our next defense object added to the toolbox. We can reference them like this: Settings.Toolbox.startX. I’ve named the values a bit generic so you can easily change the tool box from vertical to horizontal without needed to change the names to match it. In our case, we will be adding the addValue amount to the top CSS property each time we add new defense object to the toolbox.

So, our addNewDefense function takes most of its code from our initToolBox function which gets re-factored into the following:

What we have done here is take the code from inside our initToolBox loop to our new addNewDefense function. Then, we added our new Settings.Toolbox data and retrieved the current number of defense objects inside the toolbox in order to calculate the correct position for our new object. At the end of the new function, we increment our nextID variable to ensure we always get a new ID. In our last code, we would have restarted at zero each time which would have created duplicates.

Now, let’s test this method using the javascript console. In Chrome and IE the shortcut for opening the Developer Tools is F12. I believe FireFox is CTRL + SHIFT + C. Once open, find the tab titled “Console”.

Note: In Codio, switch your preview mode from “inside Codio” to “New tab” in order to use the Console properly. Alternatively, you can switch the target in Chrome dev tools from “<top frame>” to “imitate-rocket.codio.io”.

At the bottom of the console, you will find a text box to type in. Type in  addNewDefense();  and press enter.

chrome-javascript-console

You should see a new defense object added to the toolbox. Each time will result in another one being added. If you keep adding them, you will notice 10 is the most we can fit into our current sized toolbox, so let’s add a new variable in our Settings.Toolbox  object called maxDefense and set it equal to 10.

Alter our addNewDefense to exit early if we already have 10 defense objects in the toolbox.

Feel free to explore with the javascript console. Try typing in Settings.Toolbox; and hitting enter. You should see the current values of the data. This if very useful for checking values as the code is running.

Positioning Elements

If you have been following this tutorial closely, you have probably noticed this already: we are doing some clunky positioning offset math when moving defense objects from our toolbox to our stage. I was going to go back and fix this but just left it in Part 2 to point out a key factor in creating DOM based HTML5 games: Every absolute positioned element on a scene should be created at the same DOM level.

Moving the defense DIV from one container to another messes up our X and Y positioning and creates unnecessary headaches. Let’s fix that now by adding all defense objects to the “body” DOM element and using our classes to determine the current state. In production code, I would create a wrapping element to hold all of these game elements to separate from a splash/title screen but again, we will keep things simple here.

Apply these refactorings:

Add a new variable to reference the body DOM element:

In both our addNewDefense and createDefense methods, change the appendTo target to the $body variable:

Change our startX variable to 215:  Toolbox: {startX:215,...

In our addNewDefense method, append a new class inactive-defense to the new object:

And in our createDefense method, remove that class before adding the active-defense class. These two classes now determine what state (in toolbox versus on stage) our defense towers are in.

Now to wrap up this change, modify the addNewDefense function to use the new class:

and lastly modify the toolDragEnd function to get the actual position of our dragging element:

If you have been playing the output you should notice several glitches are now fixed when dropping the defense objects onto the stage.

Now, we should implement a scoring system. Let’s give 10 points for a kill and subtract 10 points if an enemy makes it off the stage area.

First, we add a new HTML element to hold the score. Let’s go ahead and add a new DIV below our current two and add some CSS rules:

Our new scorebox DIV will display the score for us. Now for a function to update the score. We will also add a variable in our Settings object to hold the current score value.

We initially call  updateScore to set our display to 0. You can type this function into the javascript console to test that it actually works. Give it a negative number to ensure that it subtracts properly as well.

Now, we need to call this in a few places. One is in our collision detection routine to add points.

The other place is our animateEnemy function. We will need to add a param that executes a function on completion of the animation which if called, we know the enemy didn’t get hit and therefor we need to subtract points. I’ve added class named “hit” in the collision detection routine and use it to determine if we should subtract points in the enemy’s animation complete method because even though we remove the enemy upon collision, TweenMax keeps it around for a bit longer in order to complete the animation. We could store a reference to the animation and kill that too, but that’s for another day.

Our updated animateEnemy and enamyComplete now remove our enemies once they reach the bottom of the screen.

Now, we just need a method of sending more waves of enemies! We started off with a basic for loop that adds five enemies to the screen. Let’s wrap that in a function, and then call it recursively to keep adding enemies.

And now we will add new towers every 100 points.

 

Notice the addition of a new Settings variable. We need to clean up one last thing, and that is our bullets that don’t hit anything. We need to remove them. We can use the onComplete parameter of the animation to accomplish this.

And now we have a fully playable game! Congratulations!

Of course, it isn’t very fun at this point. In the next session of our tutorial, we will insert some randomness and slowly increasing wave times to make the game challenging. Thanks for sticking around to Part 3.

You can continue to Part 4 or discuss in our forums.

agrothe (9 Posts)

Andrew Grothe is an enterprise developer with an interest in HTML5 mobile and game development. Andrew is current working on a casual HTML5 game at http://spacecutegame.com and maintains the http://webapplist.info website.