How to Make a Sweet HTML5 Game

by William Malone
HTML5 Game Resize Example

We are to go step by step through the process of making an HTML5 game. In our game the Sugar Overload is waging war against our humble vegetable village. As the struggle unfolds we will reveal the JavaScript code that is fueling the shower of popsicles raining down upon the populace. Only you can save the world with help from HTML5 and JavaScript.

A downloadable demo of the game is available at the bottom of the article.

Let's Prepare

We are going to use the BlocksJS game framework to simplify a few things for us. If you want to use a different framework or none at all don't worry, the sections marked with question marks will shed light on how BlocksJS implemented that particular feature or point to article with step by step instruction on coding in native JavaScript.

First let's download the BlocksJS game framework from GitHub. Download

Then let's create an HTML file and inside the head tag include the BlocksJS CSS file we just downloaded. For this article we will use build 0.5.11.

<link rel="stylesheet" href="css/blocksjs-0.5.11.min.css">

Inside the body tag of our HTML file we are going to add a container element with class name of "BlocksGame" and include the BlocksJS JavaScript file we just downloaded.

<div class="BlocksGame"></div>
<script src="js/blocksjs-0.5.11.min.js"></script>

Lastly we create a BLOCKS.game using JavaScript. Passing in an object with width and height properties will set the dimensions of our game to 800 by 600 pixels.

var game = BLOCKS.game({
  width: 800,
  height: 600
});

The Invasion Begins

Now that we have the framework of our game created we can start the next step of dropping popsicles.

Let's start by adding a background of a screne landscape of grass and clouds.

HTML5 Game Image
sweet-drop-bg.png

To make the background we create a BLOCKS.slice with the filename assigned to the src property of the parameter's object.

bg = BLOCKS.slice({
  src: "images/sweet-drop-bg.png"
});

We want the background to be rendered on the bottom layer so we set the slice's layer property the game layer with an index of 0. Lastly we add the slice to the game stage so that the background will render as part of the game loop.

bg.layer = game.layers[0];
game.stage.addView(bg);

Let's create a dropPopsicle function so we can start dropping popsicles.

var dropPopsicle = function () {

Similar to how we created the background we are going to create our first popsicle. The only difference from the background is that our popsicle has two states: one when it's falling and another when it's crashed on the ground.

HTML5 Game Image
creamsicle.png
HTML5 Game Image
creamsicle-broken.png

To make the popsicle we create a BLOCKS.block instead of a BLOCKS.slice. A block does everything a slice does but it supports multiple states. In fact, a block can be composed of slices. Since our popsicle has two different states we can treat it as a single block and when it his the ground we simply change to its "crashed" slice. We define the block's two slices with the filename assigned to the src property and the name of the slice assigned to the name property.

var popsicle = BLOCKS.block({
  slices: [{
    name: "falling",
    src: "images/creamsicle.png"
  }, {
    name: "crashed",
    src: "images/creamsicle-broken.png"
  }]
});

We want the popsicle to be rendered above the background layer (layer 0) we assign its layer property to the game layer with an index of 2. As before we add the block to the game stage so that the popsicle will render as part of the game loop.

popsicle.layer = game.layers[2];
game.stage.addView(popsicle);

Now we have a function from which we can spawn new instances of popsicles that will rain terror on our village. When we spawn a new popsicles we don't want it to drop from the exact same place so we use Math.random, which will return a random number between 0 and 1 (well acutally 0.999999...). By multiplying our random value with the width of the screen we get a random x position on the screen. And since we don't want a popsicle to be partially off the right side of the screen we multiple by the game width minus the popsicle width.

HTML5 Game Image
Popsicle Drop Start Locations

The popsicle's y position is set to minus the height of the popsicle. This will place the popsicle just off the top of the screen.

popsicle.x = Math.random() * (game.width - popsicle.width);
popsicle.y = -popsicle.height;

The next step in our dropPopsicle is to animate the popsicle from its starting position to the ground.

HTML5 Game Image
Popsicle Drop Animation

To animate the popsicle we add a y motor using the game's addMotor method. This will translate the popsicle in the y direction simulating dropping from the sky. We set the object property to our popsicle variable, the duration property to 3000 milliseconds (3 seconds), and the amount property to the game height minus a little margin so it doesn't land right at the edge of the screen. We also set the easing property to a value of "easeIn" to roughly simulate gravity by slowing the animation at the beginning.

The value of the callback property of the addMotor method will invoke a function once the animation has completed. In this anonymous function we change the popsicle to its "crashed" slice will display the "crashed" version of the popsicle image.

game.addMotor("y", {
  object: popsicle,
  duration: 3000,
  amount: game.height - 20,
  easing: "easeIn",
  callback: function () {
    popsicle.setSlice("crashed");
    game.addTicker(melt, 2000);
  }
}

Inside the callback function we also create a ticker which will invoke the melt function after a couple seconds to remove the destroyed popsicle from the game.

In the heat of our serene landscape our popsicle won't stay on the ground long. A couple seconds after collision each popsicle instance invokes the melt function. The melting process adds three motors to the popsicle block which will tween 3 properties: alpha, cropHeight, and y position.

HTML5 Game Image
Popsicle Melt Animation

To tween the popsicles properties to simulate melting we will add motors for each property:

  • The alpha motor will tween the transparency of the popsicle from fully opaque to transparent.
  • The y motor will move the popsicle down by one popsicle height.
  • The cropHeight motor will crop the bottom of the popsicle as it melts.

We will set an easing value of "easeIn" like we did with the popsicle to slow the beginning of the animation.

var melt = function () {

  game.addMotor("alpha", {
    object: popsicle,
    duration: 800,
    amount: -1,
    easing: "easeIn",
    callback: function () {
      game.stage.removeView(popsicle);
      popsicle.destroy();
      popsicle = null;
    }
  });
					
  game.addMotor("y", {
    object: popsicle,
    duration: 1000,
    amount: popsicle.height,
    easing: "easeIn"
  });

  popsicle.cropHeight = popsicle.height;
  game.addMotor("cropHeight", {
    object: popsicle,
    duration: 1000,
    amount: -popsicle.height,
    easing: "easeIn"
  });

After the melt is complete we will destroy the popsicle from the world and from memory. To do this we add a function to the callback of one of the motors. The destruction of the popsicle involves removing the block from the game stage, invoking the destroy method and finally removing all reference to the popsicle instance by setting it to null.

Calling Reinforcements

Domination of the world would benefit from more than one type of popsicle:

HTML5 Game Image
bomb-pop.png
HTML5 Game Image
bomb-pop-broken.png
HTML5 Game Image
popsicle.png
HTML5 Game Image
popsicle-broken.png
HTML5 Game Image
push-up.png
HTML5 Game Image
push-up-broken.png

To support additional popsicles we define the popsicle specification just like we did with the creamsicle but this time we place the definitions into an array we are calling spec.popsicles. This gives access to additional popsicles named: "bombpop", "popsicle" and "pushUp".

spec.popsicles = [{
  name: "creamsicle",
  slices: [{
    name: "falling",
    src: "images/creamsicle.png"
  }, {
    name: "crashed",
    src: "images/creamsicle-broken.png"
  }]
}, {
  name: "bombpop",
  slices: [{
    name: "falling",
    src: "images/bombpop.png"
  }, {
    name: "crashed",
    src: "images/bombpop-broken.png"
  }]
}, {
  name: "popsicle",
  slices: [{
    name: "falling",
    src: "images/popsicle.png"
  }, {
    name: "crashed",
    src: "images/popsicle-broken.png"
  }]
}, {
  name: "pushUp",
  slices: [{
    name: "falling",
    src: "images/push-up.png"
  }, {
    name: "crashed",
    src: "images/push-up-broken.png"
  }]
}];

To fully access our sugar arsenal we again turn to Math.random. We multiple by the length of the spec.popsicles array and then Math.floor that value and we end up with a random index (i.e. 0, 1, 2 or 3). The following code will create a random popsicle block from the array we just made.

var popsicle = BLOCKS.block(spec.popsicles[Math.floor(Math.random() * spec.popsicles.length)]);

We need to actually drop the popsicle. We do this by calling the dropPopsicle function.

dropPopsicle();

To keep it raining popsicles we need to add ticker at the end of the dropPopsicle function. This will ensure that the popsicles will keep coming. The second parameter of the addTicker method is the delay before calling the function. In this demo we are going to really make it rain by dropping a popsicle twice per second or 500 milliseconds.

game.addTicker(dropPopsicle, 500);

The following demo randomly drops popsicles all over the place.

It Takes a Village

There wouldn't be destruction without something to destroy. Let's create some structures.

HTML5 Game Image
tent.png
HTML5 Game Image
tent-hit.png
HTML5 Game Image
tent-broken.png

First we create a new block inside a function called spawnStructure. Since our structure has three different states we define three different slices in the slices array of the new block. Each slice definition includes the name of the slice ("inactive", "active" and "broken") and the filename of the slice's image via its src property.

spawnStructure = function () {

  structure = BLOCKS.block({
    name: "tent",
    slices: [{
      name: "inactive",
      src: "images/tent.png"
    }, {
      name: "active",
      src: "images/tent-hit.png"
    }, {
      name: "broken",
      src: "images/tent-broken.png"
    }]
  });

Let's put the structures on layer with index of 1 so it will be above the background (layer 0) and behind the popsicles (layer 2). And lastly we add the structure to the game stage via its addView method.

structure.layer = game.layers[1];
game.stage.addView(structure);

Let's randomly position the x position of the new structure just like we did with the popsicles before. We set the y to the location of the ground. We also initialize a numHits property which we will use later to keep track of the number of times a structure is hit by a popsicle.

structure.x = Math.random() * (game.width - structure.width * 2) + structure.width / 2;
structure.y = game.height - 20;
structure.numHits = 0;

Instead of a new structure just appearing out of nowhere let's have it animate into existence.

HTML5 Game Image Example
Spawning Structure Animation

We can animate the spawning of the structure by adding a couple motors:

  • The y motor will move the structure in the y direction. We set the duration property to 500 milliseconds and the amount property to the negative height of the structure. The easing property of "easeOut" will slow the animation near the end.
  • The cropHeight motor will crop the tent to simulate it coming out of the ground. We set the same property values as the y motor except we use a positive value of the structure height since we want the cropHeight to increase as it animates.
game.addMotor("y", {
  object: structure,
  duration: 500,
  amount: -structure.height,
  easing: "easeOut"
});

structure.cropHeight = 0;
game.addMotor("cropHeight", {
  object: structure,
  duration: 500,
  amount: structure.height,
  easing: "easeOut"
});

structures.push(structure);

Collision Detection

Now that we have structures in the game let's destroy them!

To determine if the popsicle has landed on one of the structures we will use collision detection. There are many different types of collision detection; in this case we will use a rectangle-rectangle technique. We will be comparing the bounding box (a rectangle with the same position and width and height) of the popsicle and bounding box of the structure. If the two rectangles overlay in any way then we consider a collision detected.

HTML5 Game Collision Detection Example
Example of Collision Detection

To make things a bit easier we are only going to check this once, when the popsicle lands. That collision test will need to be done on all the structures in a simple for loop once the popsicle hits the ground.

for (i = 0; i < structures.length; i += 1) {
  if (popsicle.isRectInside(structures[i])) {
    ...
  }
}

Using the BlocksJS isRectInside method which is available on any view (e.g. block or slice) we compare the bounding box of the popsicle with the bounding box of each structure.

When a collision is detected we increment the numHits property of the structure we collided with.

structures[i].numHits += 1;

The first collision changes the color of the structure for a moment, the second collapses it.

HTML5 Game Collision Detection Example
Structure Collision States

The first time the structure is hit (aka the numHits property is 1) then we are going to set the structure's slice to "active". This will change the structure image to the red tent.

HTML5 Game Image
tent-hit.png

We also added a ticker that will call the resetStructure after 2500 milliseconds to change it back to its original color.

if (structures[i].numHits === 2) {
                   	
  structures[i].setSlice("active");
	
  game.addTicker(resetStructure, 2500, structures[i]);
  
  ...

The resetStructure function will reset our "active" (red) structure to its "inactive" (brown) slice. However we need to be careful; by the time the function is called another popsicle could have hit the structure and collapsed it. If that happened the structure would be in the "broken" (collapsed) state so we wouldn't want to change it back to its "active" (red an uncollapsed) state. Fortunately we can determine the structure's current state using the block's getSlice method. It returns the block's active slice. We can read that active slice's name property to determine what slice is currently being display. That way we only reset the structure if the slice's name property is equal to the string "active".

resetStructure = function (structure) {
  if (structure.getSlice().name === "active") {
    structure.setSlice("inactive");
  }
};

If the structure has been hit twice (aka the numHits property is 2) then we are going to set the structure's slice to "broken". This will change the image of the tent to its collapsed version.

HTML5 Game Image
tent-broken.png

We also added a couple of tickers that will both destroy the structure and then spawn a new one.

} else if (structures[i].numHits === 2) {
  					
  structures[i].setSlice("broken");

  game.addTicker(destroyStructure, 3500, structures[i]);	
  game.addTicker(spawnStructure, 3500); 
}

Just like how we destroyed the popsicle we remove the structure's block from the stage, call the destroy method, and remove the structure from the structure array.

destroyStructure = function (structure) {

  var i;

  for (i = 0; i < structures.length; i += 1) {
    if (structure === structures[i]) {
      structures.splice(i, 1);
      break;
    }
  }
  game.stage.removeView(structure);
  structure.destroy();
  structure = null;
},

Now we watch the destruction ensue in our second demo.

The Hero in All of Us

We have idly watched the destruction of our village for too long. It is time we fight back!

To stop the popsicle invasion we need to tap those popsicles to smithereens. Adding an event listener to the game's controller object will allow us to invoke a function when a user clicks with a mouse or a touches the screen on a touch device. Both events are abstracted into a "tap" event. We add the string "tap" and the function gameTapped as parameters of the controller object's addEventListener method. This will call the gameTapped function whenever a "tap" event is fired.

game.controller.addEventListener("tap", gameTapped);

Earlier, to determine if a popsicle and structure collided, we used rectangle-rectangle detection. To determine if a popsicle and tap collide we will use point-rectangle collision detection because unlike the structure a tap is a point and not a rectangle; it only has a position not a width and height.

The gameTapped function is called every time a user taps. It only has one argument: the point object which includes the x and y position of that tap relative to the game.

To check for if the user can tapped a popsicle we loop through the array of popsicles and call each popsicle's isPointInside method. If the method returns true then we have tapped a popsicle.

gameTapped = function (point) {

  var i;

  for (i = 0; i < popsicles.length; i += 1) {
    if (popsicles[i].isPointInside(point)) {
      ...
    }
  }
},

If we tap a popsicle then we are going exact revenge in three ways.

HTML5 Game Image Example
Tap Popsicle Animation

First we stop the popsicle from dropping. We do this with the removeMotors method which will remove the y motor we added which is causing the popsicle to move.

Next we are going to fade out the popsicle. We do this by adding a new "alpha" motor. A view starts by default with an alpha value of 1 (fully opaque). By setting the motor's amount property to -1 the "alpha" motor will tween that value from 1 to 0 (fully transparent).

Finally we add a ticker that will call the function destroyPopsicle after a delay of 500 milliseconds.

popsicles[i].removeMotors();
game.addMotor("alpha", {
  object: popsicles[i],
  duration: 500,
  amount: -1
});
game.addTicker(destroyPopsicle, 500, popsicles[i]);

In our final demo it's your turn to tap those invading popsicles and save our village!

Launch Demo

This is currently the end of the article but I encourage you to take this game further. All the code and assets are available for download. Maybe the popsicles can drop at a faster rate over time. Maybe certain popsicles require more hits to destroy them. Maybe the structures are upgraded from tents to houses to bunkers each level so it requires more popsicles to destroy them. There are so many possibilities and that is what makes game development so much fun.

Download Game

You can download the demo with all the code and assets on GitHub.

Download

Share This Article

Related Articles