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.

Gengo Girls #35: The Future Is Now

Gengo Girls #35: The Future Is Now

At first the idea of not having a specific future tense might seem confusing, but look at it this way: That’s one less conjugation for you to learn.

And it’s not like it’s really that strange of an idea. In English both “I’m going to the store” and “I’m going to next week’s concert” have the same verb but I bet you didn’t have any trouble at all telling which one is happening now and which one is happening in the future.

Transcript

言語ガールズ #35

The Future Is Now

Blue: Did you know that 日本語 doesn’t have a future tense?

Yellow: Really?

Blue: 私は行きます can mean both “I go” and “I will go”.

Yellow: Then how do I tell the difference between present and future verbs?

Blue: From context.

Blue: If you say 行きます while walking out the door, that would mean “I go”.

Blue: But if we were talking about a concert happening next week and you said 行きます that would mean “I will go”.

Yellow: A concert? Of course I’m going!

Blue: There is no concert. It was just an example.

Yellow: Awww…

 

Gengo Girls #34: The Journey Is More Important Than The Destination

Gengo Girls #34: The Journey Is More Important Than The Destination

In the real world people almost never say boring things like “I go” or “The dog barks”. It’s always “I’m going to the library, be back in a minute” or “Why in the world is that dog barking so loud at 3 in the morning?”

But saying complex sentences require a lot of grammar we haven’t covered yet so for the next several strips you’re just going to have to deal with artificially boring sentences.

Vocabulary

= わたし = I; me

行く = いく = to go

Transcript

言語ガールズ #34

The Journey Is More Important

Than The Destination

Blue: Let’s try using the “Subject Verb” pattern to say “I go”.

Yellow: Let’s see… 行く doesn’t end in “iru” or “eru” so to make it polite I have to change the last syllable to and add ます.

Yellow: So “I go” must be…

Yellow: 私は行きます

Blue: Perfect!

Yellow: But where am I going?

Blue: We need to learn some new grammar before we can answer that question.

Yellow: In that case I’m going home.

Gengo Girls #33: Another Building Block

Gengo Girls #33: Another Building Block

It’s amazing how many different situations you can talk your way through using nothing but the “A is B” pattern, but eventually you’re going to need to use an actual verb. And now you can! Or at least, you can as soon as you learn some more verbs.

Transcript

言語ガールズ #33

Another Building Block

Blue: Now that you know how to make verbs polite we can learn a new sentence pattern!

Yellow: Hooray?

Blue: Our new pattern is the simple “Subject Verb” pattern.

Yellow: You mean things like “The dog barks” and “The bird sings”?

Blue: Exactly!

Blue: In 日本語 this pattern is “Subject Verb”.

Yellow: That’s almost the same as in 英語. This is easy!

Blue: One last thing: the sounds like “wa” instead of “ha”, just like in the “ABです” pattern.

Yellow: Come on , make up your mind already!

Gengo Girls #32: Fool Me Once…

Gengo Girls #32: Fool Me Once...

Wakaru is yet another super common Japanese word. It is usually used to mean that you literally do or don’t understand something, like when you want to say “I don’t understand Japanese” or “Thank you for explaining that. I understand now”.

But wakaru is also often used as a way of agreeing to requests. If your boss asked you to photocopy a document and deliver it to one of your coworkers you could say “wakarimasu” to mean “I understand your request (and will go do that now)”.

Vocabulary

分る = わかる = to understand

Transcript

言語ガールズ #32

Fool Me Once…

Blue: Verbs that don’t end in “iru” or “eru” will still end in some sort of “u” sound like or .

Yellow: That’s convenient.

Blue: To make these verbs polite you first change the final “u” sound to an “i” sound.

Blue: to , to , to and so on.

Blue: Then you add ます to the end.

Blue: Let’s look at わかる. It ends in “aru”, not “iru” or “eru”, so we can’t just replace the with ます.

Yellow: Instead we have to change the to and then add ます, right?

Blue: Exactly! So the polite form of わかる is わかります.

Yellow: I understand…

Blue: I’m not falling for that gag a second time.

Gengo Girls #31: I See What You Did There

Gengo Girls #31: I See What You Did There

Look at you, conjugating verbs and everything. Just a few more lessons and we’ll finally be able to say something other than “A is B”. How exciting.

Vocabulary

見る = みる = to see

Transcript

言語ガールズ #31

I See What You Did There

Blue: The easiest verbs to make polite are the ones that end in an “iru” or “eru” sound.

Blue: The “ru” has to be but the “i” and “e” can be part of another symbol like or .

Blue: To make these verbs polite all you have to do is replace the with ます.

Yellow: I think I can handle that.

Blue: Here’s an example: みる becomes みます.

Yellow: I see.

Blue: That’s one possible translation.

Yellow: Translation of ?

Blue: No, a translation of 見ます.

Yellow: What’s a 見ます?

Let’s Program A JavaScript Game 9: Look Before You Leap

Avoiding Un-win-able Games

 

Now it’s time to actually put together a stage, with gaps for the player to jump over and everything.

 

The most important element here is making sure that the gaps are small enough that the player can always jump over them. It’s neither fun nor fair to hit the player with an impossibly large obstacle.

 

So that means we have to figure out how far the player can jump, which depends on two things: 1) How long the player is in the air 2) How fast the player is moving forward while in the air.

 

For example, if the player’s jump leaves him in the air for two seconds and the player is moving 100 pixels per second the player can safely jump a 200 pixel gap.

 

Now we already know that our player can move 5 pixels to the left or right per frame. But to figure out how long they can stay in the air we’re going to need to do a little math.

 

You might remember from physics that a moving object’s position can be described by the equation: current position = starting position + velocity * time + ½ acceleration * time^2.

 

Now this equation doesn’t quite match our frame-based game world physics, but it will still give us a close estimate. So let’s plug in some numbers and find out how long it takes for an object to reach the ground (position 0) if it starts at position 0 with a velocity of -15 pixels per second and an acceleration of 1 pixel per second per second.

 

0 = 0 – 15t + ½t^2.

15t = ½ t^2

15=1/2t

t=30

 

According to this our cycle’s jump takes 30 frames, or about a second and a half, to complete. And from testing the code so far that feels about right.

 

So 30 frames of airtime while moving 5 pixels to the right per frame means our cycle can move 150 pixels in one jump.

 

To test this I’m going to shrink the current “ground” testObject to only fill a third of the screen and then insert a second testObject2 150 pixels further to the right. I will then add code for testing collisions with testObject2 so I can practice jumping between them.

 

I’m also going to add code to detect when the motorcycle has fallen off the bottom of the screen. Eventually we’ll want this code to trigger some sort of game over message but for now we’ll just have it drop the cycle back into starting position. It would be a real pain to have to reload the game testing page every time we fell off the screen.

 

This code goes near the top of your script, before any function declarations:

 

var testObject = new Object();
testObject.x = 0;
testObject.y = 350;
testObject.width = 200;
testObject.height = 20;

var testObject2 = new Object();
testObject2.x = 350;
testObject2.y = 350;
testObject2.width = 200;
testObject2.height = 20;

 

And the drawScreen function needs to be changed like this to draw two rectangles instead of just one:

 

//Draw red squares the player can jump on
context.fillStyle = '#FF0000';
context.fillRect(testObject.x, testObject.y, testObject.width, testObject.height);
context.fillRect(testObject2.x, testObject2.y, testObject2.width, testObject2.height);

 

And the collision detection section of the updateGame function needs to be changed to this:

 

if(intersectRect(testObject, getFeetHitbox(player.x, player.y))){
   feetCollision = true;
   player.yVel=0;
   player.y=testObject.y-48;
   player.onGround=true;
}

if(intersectRect(testObject2, getFeetHitbox(player.x, player.y))){
   feetCollision = true;
   player.yVel=0;
   player.y=testObject2.y-48;
   player.onGround=true;
}

if(intersectRect(testObject, getDeathHitbox(player.x, player.y))){
   deathCollision = true;
}

if(intersectRect(testObject, getGrazeHitbox(player.x, player.y))){
   grazeCollision = true;
}

//Reset the player to default location when they fall off the screen
if(player.y > 400){
   player.x = 100;
   player.y = 100;
}

 

Run the game now and you can jump between the two red platforms and confirm that 150 pixel jump is just about right for jumping distance.

 

Next Time: Lot’s More Platforms

 

With this little bit of prep work out of the way we can finally write some code to automatically generate and position hundreds of platforms. This game will finally start feeling like a game!

Gengo Girls #30: Dreaming Of A White Christ-masu?

Gengo Girls #30: Dreaming Of A White Christmasu?

 

Ganbaru in it’s various conjugated forms is another word that’s really easy to pick out in Japanese media. It’s a common phrase that gets used anytime someone wants to wish someone else good luck (try your best). Or encourage someone who is having a tough time (keep trying). Or compliment someone on a job well done (you did your best (and it worked)). Or to console someone who failed (you did you best (even though it didn’t work out)).

It’s basically a super word that can be pulled out anytime hard work and fighting spirit is involved. And I think it says a lot about Japanese culture that their version of “good luck” is more literally translated as “go work really hard”.

Vocabulary

頑張る = がんばる = to try your best

Transcript

言語ガールズ #30

Dreaming Of A White Christ-masu?

Blue: The dictionary form of a verb and the polite form both start the same way, but the polite form will always end in ます.

Blue: For example: look at the 日本語 verb for “to try your best”.

Blue: The dictionary form is がんばand the polite form is がんばります.

Yellow: They do sound pretty similar.

Blue: Be aware that most people pronounce ます more like “mas” than “masu”.

Yellow: Oh! Just like how です sounds more like “des” than “desu”!

Blue: So, are you ready to learn the rules for making polite verbs?

Yellow: Yeah! Let’s 頑張ります!

Blue: That’s the spirit!

 

Gengo Girls #29: That’s Just How Life Is

Gengo Girls #29: That's Just How Life Is

 

If you got into Japanese from watching anime or playing games odds are good you hear casual (or even vulgar) Japanese a lot more often than formal Japanese, which isn’t a bad thing per se. Just don’t let it influence the way you talk to actual Japanese people.

As for this whole polite verb thing: as an English speaker you should already be used to the idea that certain words are more polite than others. You might tell a friend that your car “is all busted up” but if a police officer wanted to know why you were walking along the side of the road you would probably say something more like “my car broke down a few miles back”.

In Japanese it’s the same idea, except that you have the choice between not only polite and casual words but polite and casual ways to say each word. The polite and casual forms of the verb “broke” both mean the same thing but when describing how your car broke down you would use the polite form for your mechanic, coworkers or a police officer and save the casual form for telling your best friend how your car broke down and ruined your day.

Transcript

言語ガールズ #29

That’s Just How Life Is

Blue: Respect is such a big part of 日本語that it even affects how verbs are conjugated.

Blue: Specifically, all verbs come in both a “dictionary” form and a “polite” form.

Blue: The polite form is used for doing business and for conversations between adults that aren’t close friends.

Blue: Foreigners like us use the polite form for both work and sightseeing, so we should practice it extra hard.

Yellow: Does that mean I can ignore the dictionary verb forms?

Blue: You need to know those too. Dictionary form is used in a lot of books, pamphlets, websites, TV shows and games.

Yellow: I have to learn about both types of verbs even though I’m only allowed to use one of them?

Yellow: That’s not fair!

Blue: Why are you looking at me like that? How is this my fault?!

 

Gengo Girls #28: Multilayer Cultural Barrier

Gengo Girls #28: Multilayer Cultural Barrier

It’s often said that the Japanese are more polite than us Americans, and it’s probably true. But a big part of this comes from the fact that the Japanese have a very different definition of “polite” than we’re used to.

Here in America our country was based around the idea that “all men are created equal”. As a result we consider it really rude when a person tries to act superior by insisting on a specific title. A PhD might prefer to be called “Doctor” but if he makes too big a deal out of it we would consider him to be acting impolite. In many parts of the country we actually prefer it when people are casual and feel insulted when people are too formal.

Japan, on the other hand, has a history full of military empires where rank was everything. As a result their language is full of different ways tot show respect and it’s considered very rude to not use language that clearly identifies the difference between superiors vs inferiors or friends and family vs casual acquaintances. Now that Japan’s military government has been replaced by a modern democracy “superior” is more likely to mean a senior coworker than a nearby warlord but the tradition of respecting even small differences in social rank is still going strong.

Transcript

言語ガールズ #28

Multilayer Cultural Barrier

Blue: Pop Quiz: A man has just introduced himself as たなか ひろ. What do you call him?

Yellow: That means たなか is his family name, so I would call him たなかさん.

Yellow: But is this name and title stuff really that important?

Blue: It is. In 日本 first names are reserved for friends and family.

Blue: Using someone’s first names is kind of like calling them “Pal” or “Sweetie”.

Blue: It’s fine between friends and family but kind of awkward with strangers or coworkers.

Yellow: Where I grew up it was pretty normal to call strangers “Sweetie”. Showed we were friendly.

Blue: Looks like we’re dealing with more cultural barriers here than I thought.