Let’s Program A JavaScript Game 10: Letting The World Pass By

A World, Or The Illusion Of A World?

Our end goal is to let the player spend two or three minutes jumping from platform to platform and avoiding viruses. But how do we go about accomplishing this?

My first instinct was to build a hundred or so platforms and position them around the game world. Then for each frame of the game we would check whether or not the player had hit any of the platforms and finish up by drawing any platforms that were currently on screen.

And this would work. Keeping track of a few hundred objects and possible object collisions is no sweat for a modern computer.

But there are a few reasons that keeping track of an entire world of platforms might not be such a great idea for this particular game:

  • We only have room for two or three platforms on the screen at one time. Keeping track of the extras is a waste (even if it is one we can afford)
  • The player can never move backwards so we don’t have to keep track of platforms we have already passed.
  • Building an entire world ahead of time would make it impossible to adjust the game for players who are doing well. Players who get a lot of graze points should start finding small platforms and big gaps much earlier than players who don’t. Otherwise they might win the game through graze points without ever hitting any difficult jumps.

So instead of creating an entire world of platforms I’m only going to create a list of 5 platforms. When a platform gets left behind by the player I will delete it and then generate a new platform to add to the end of the list.

To the player this will still look like a complete world with hundreds of platforms. There will always be two or three platforms on screen and there will always be a new platform waiting for them as they move to the right. The player will never know that platforms are disappearing behind them or that they are popping into existence mere seconds before they are needed.

All Motion Is Relative

Now that we’ve decided how to build the platforms we also have to decide how we’re going to scroll the screen. After all, the entire game is based around the player constantly moving to the right.

You might think that if the game is about the player moving to the right the only solution is to make the player actually move to the right, maybe by increasing their x position by a constant amount every turn. But if we do that the player would eventually drive right off the right side of the screen, which would be bad.

So instead of moving the player forwards we’re going to move the entire world backwards. It’s not even that hard to do. Every frame we just iterate through out list of five platforms and adjust their x position backwards.

Infinite Platforms Demo

To put this all into play we need to make the following changes to our code:

  • Create a list of platforms
  • Populate the list with five starter platforms
  • Move those platforms to the left during each frame
  • Check for player collision with all five platforms during each frame
  • Delete platforms that scroll entirely off the screen
  • Add a new platform to the end of the list every time one gets deleted from the front
  • Draw any platforms that happen to be on screen

Let’s start by creating and populating the platform list. This code goes before any function declarations and replaces our old testObject1 and testObject2 declarations:

var platforms = new Array();
var maxPlatformCount = 5;
var maxPlatformLength = 200;
var maxPlatformGap = 150;

//Generate starting platforms
for(i = 0; i < maxPlatformCount; i++){
   var newPlatform = new Object();
   newPlatform.x = i * (maxPlatformLength + maxPlatformGap);
   newPlatform.y = 350;
   newPlatform.width = maxPlatformLength;
   newPlatform.height = 20;
   platforms[i] = newPlatform;
}

Now we need to go down to our updateGame method and replace our testObject collission code with this:

var feetHitbox = getFeetHitbox(player.x, player.y);

//Platform logic
for( i = 0; i < platforms.length; i++){
   //Create illusion of player moving forward by scrolling all platforms backwards
   platforms[i].x-=5;

   //See if the player has landed on this platform
   if(intersectRect(platforms[i], feetHitbox)){
      feetCollision = true;
      player.yVel=0;
      player.y=platforms[i].y-48;
      player.onGround=true;
   }
}

Few things to notice: We now create one set of player hitboxes per frame and then use them multiple times inside the loop. This is slightly more efficient than creating the hitboxes multiple times inside the loop.

We are also using the loop to both update the position of each platform and check for platform collisions. This is slightly more efficient than having two seperate loops: one for updating position and one for checking for collisions.

Now we can draw the platforms by replacing the testObject related drawing code in drawScreen with this:

//Draw platforms
context.fillStyle = '#008800';
for(i = 0; i < platforms.length; i++){
   context.fillRect(platforms[i].x, platforms[i].y, platforms[i].width, platforms[i].height);
}

Now if you try to actually run the game at this point you should see five moving platforms… but as soon as they all scroll past the screen you get stuck in an endless loop of falling of the screen again and again and again. Let’s fix that by going back up to updateGame and adding in code to remove old platforms and add new ones in. This particular code should come right after the end of the foreach loop we used for updating the platforms:

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

   //Add new platfrom to end of list by placing it a certain distance after second to last platform
   var newPlatform = new Object();
   newPlatform.x = platforms[platforms.length-2].x + maxPlatformLength + maxPlatformGap;
   newPlatform.y = 350;
   newPlatform.width = maxPlatformLength;
   newPlatform.height = 20;
   platforms[platforms.length-1] = newPlatform;
}

And that’s that. You now have an infinitely scrolling world of platforms and gaps. It’s a pretty boring world, to be honest, and we’ll definitely want to mix things up a little before giving this to an actual player. But as a piece of proof of concept code this all pretty good.

Jump. Jump. Jump. Forever.

Jump. Jump. Jump. Forever.

Feeling Lost? Here’s A Map

My last few posts have included a lot of instructions to “delete this” and “insert that” and I’ll admit that can be vague and confusing. So here’s a snapshot of my code right now. Follow the link to try it out or save it to your computer to read through my code. Just put it in the same folder as the cycle.png image and it should run just fine.

Things Are About To Get More Dangerous

With platforms live and moving the next major feature to work on are the deadly viruses that the player is supposed to avoid and graze. So tune in again next time to see how that works out.