Let’s Program A JavaScript Game 11: This Post Isn’t About Malware, Honest

Let’s Get Dangerous

We have a cycle for the player and an endlessly scrolling screen of platforms for them to jump along. The only piece we’re missing are the deadly virus enemies for the player to avoid.

Viruses are going to be implemented more or less the same as platforms. We’ll have an array of viruses that scroll that to the left. When a virus has moved entirely off screen we drop it from the front of the list and then pin a new virus to the back of the list. In the future we will randomize the location and timing of new viruses to make things a little less predictable but for now a couple viruses marching in a steady line will let us test everything we need to test.

Writing Simple Enemies

The code for the virus obstacles is almost identicle to the code for the platforms. Generate an array of objects, move them a little to the left every frame and check for collisions with the player. So nothing here should be especially mind blowing.

First up, we generate the original list of viruses at the top of code by putting this code right after the platform setup code:

var viruses = new Array();
var virusStartingOffset = 1000;
var maxVirusCount = 2;
var maxVirusGap = 400;
var virusWidth = 50;
var virusHeight = 50;

//Generate starting viruses (all off screen at first)
for(i = 0; i < maxVirusCount; i++){
   var newVirus = new Object();
   newVirus.x = virusStartingOffset + i * (virusWidth + maxVirusGap);
   newVirus.y = 200;
   newVirus.width = virusWidth;
   newVirus.height = virusHeight;
   viruses[i] = newVirus;
}

You also need to include this image related code somewhere so we can draw the viruses. I suggest putting it right after the cycle image code:

var virusImage = new Image();
virusImage.src = "virus.png";

Next up is adding virus code to the updateGame method. Just drop this in right after the big block of platform code:

//Virus logic
for( i = 0; i < viruses.length; i++){
   //Have all viruses move towards the player
   viruses[i].x-=5;
   
   //See if the player is grazing this virus
   if(intersectRect(viruses[i], grazeHitbox)){
      grazeCollision = true;
   }

   //See if the player has had a lethal collision with this virus
   if(intersectRect(viruses[i], deathHitbox)){
      deathCollision = true;
   }
}

//Remove viruses that have scrolled off screen and create new viruses to take their place
if(viruses[0].x + viruses[0].width < 0){
   //Drop first virus by shifting entire list one space left
   for( i = 0; i < viruses.length-1; i++){
      viruses[i] = viruses[i+1];
   }

   //Add new platfrom to end of list by placing it a certain distance after second to last platfor
   var newVirus = new Object();
   newVirus.x = viruses[viruses.length-2].x + virusWidth + maxVirusGap;
   newVirus.y = 200;
   newVirus.width = 50;
   newVirus.height = 50;
   viruses[viruses.length-1] = newVirus;
}

And finally we draw the viruses by adding this simple loop somewhere in our drawScreen method

//Draw viruses
for(i = 0; i < viruses.length; i++){
   context.drawImage(virusImage, viruses[i].x, viruses[i].y);
}

That’s it. You now have a couple of virus obstacles scrolling across the screen along with the platforms. You can jump near them and into them and watch your “graze” and “death” collision status change. These collisions won’t actually do anything yet, but just keeping track of them is the first step towards building a real game-over and bonus point system.

Both “Graze Collision” and “Death Collision” are true, showing we got just a little too close during this test

Both “Graze Collision” and “Death Collision” are true, showing we got just a little too close during this test

Why We Did What We Did

This entire branch of code was mostly just copy pasting the platform code and then renaming the variables, so no big ideas need to be explained. But there was one tiny design decisions that I think deserve a little extra analysis: Why did we give each virus a specific height and width instead of just using the height and width of the global virus image?

Two big reasons.

Reason one: Our collision detection function expects to be given two rectangle like objects that know their own x position, y position, width and height. Giving every virus a copy of this information means we can drop them directly into the collision detection function.

Reason two: We may not want our viruses to always be the same size as their picture. In the future we might decide that we want the virus’s collision box to be smaller than the virus picture in order to make collisions easier to avoid. So by keeping the virus’s height and weight independent form the size of the graphics we draw we give ourselves the freedom to make major changes in the future without breaking anything.

Next Up: Game-Over

With most of the basic game mechanics in place the next thing to do is finally let player’s lose, which is a surprisingly big tasks since it means we will have to introduce ideas like “game states” and “multiple possible screen renderers”.

But don’t worry, it’s actually a pretty simple once you get into it. And it involves flowcharts! Everyone loves flowcharts!