Let’s Program A JavaScript Game 5: Press Start To Play

Play A Game Or Watch A Movie?

 

Pop Quiz: What’s the main difference between a movie and a videogame?

 

If you answered “Player Input”: Congratulations, you’re exactly right! The main component that makes a game a game is the fact that the player has some control over what happens next. The player isn’t just watching some hero fight a monster, he’s pressing the buttons that make the hero fight.

 

If you answered anything else: You’re probably still right but that wasn’t the answer I was looking for so it doesn’t count. Try to do a better job of reading my mind next time I ask a semi-rhetorical question.

 

Anyways, my main point here is that player’s input is important and that’s what I’m going to be programming today.

 

Getting Input With JavaScript A.K.A. Whoops I Lied To You

 

Remember how we prototyped a getInput function and put it at the start of our gameLoop? Turns out that doesn’t work so great with JavaScript. Throw away that function and all references to it, we’re going to be doing something completely different.

 

Don’t look at me like that. This is a Let’s Program, I’m writing these articles at the same time as the code and I don’t always catch my mistakes early enough to fix them before hitting “post”.

 

Anyways, here is how it should work:

 

Instead of checking for input during the loop we will ask the browser to run a short piece of code every time a key is pressed. Of course, we may not be ready for player input at that exact moment so we will just have the code store the input for future use. That way if a player presses a key between game loops the input will still be there the next time we update.

 

As for the potential issue of the player pressing a key during a game loop… it’s not really a problem. Modern browsers can run multiple pieces of JavaScript at once so we don’t have to worry about the game lagging because it is trying to update the game and process input at the same time.

 

There is still the slight issue of what happens if player input changes halfway through a loop. Maybe the loop starts with the “right” key being pressed and then halfway through the key is released. This could lead to a strange state where we do 50% right key logic and 50% default logic. To prevent this we’ll just have to be sure that we only access player input once per loop so that it doesn’t have time to change on us, maybe by storing a local copy of player input at the start of every loop so that the global input can change without influencing the current frame.

 

Time For The Code

 

First off we have to let the browser know that we want the input. One easy way to do this is by adding onkeyup and onkeydown traits to the body tag in your HTML. Just change your code from this:

 

<body>

 

to this:

 

<body onkeydown="doKeyDown(event);" onkeyup="doKeyUp(event);">

 

Now everytime the user presses a key the browser will automatically run the doKeyDown function we’re about to write. And when they release a key it will automatically run the doKeyUp event that we are also about to code.

 

One warning: This will capture ALL keyboard input for that page, which is OK for a full page game but can be a bad idea if your game is just one part of a much larger page where people might want to use their keys for scrolling.

 

Capturing input doesn’t do us any good if we don’t have a place to store it, so let’s start by adding a new object declaration to the top of our script:

 

var playerInput = new Object()

 

Now we can write the doKeyDown and doKeyUp functions. They’re both pretty simple functions, with the only trick being that we have to double check whether the user is using Internet Explorer or not because certain code only works on certain browsers. Other than that we just check the numeric code of whatever button the user just pressed, see if the code matches any of the arrow keys and then record it in our playerInput variable.

 

function doKeyDown(event){
   var keynum;

   if(window.event){ //Browser is IE
      keynum = event.keyCode;
   }
   else{
      keynum = event.which;
   }

   if(keynum == 37){
      playerInput.left = 1;
   }
   else if(keynum == 38){
      playerInput.up = 1;
   }
   else if(keynum == 39){
      playerInput.right = 1;
   }
   else if(keynum == 40){
      playerInput.down = 1;
   }
}

function doKeyUp(event){
   var keynum;

   if(window.event){ //Browser is IE
      keynum = event.keyCode;
   }
   else{
      keynum = event.which;
   }

   if(keynum == 37){
      playerInput.left = 0;
   }
   else if(keynum == 38){
      playerInput.up = 0;
   }
   else if(keynum == 39){
      playerInput.right = 0;
   }
   else if(keynum == 40){
      playerInput.down = 0;
   }
}

 

Of course, if you are building a game that uses buttons other than the arrow keys you will need more else if statements for whatever buttons you are interested in. For example, maybe you want your running game to let the user use the spacebar to jump. To do so you’d just have to lookup the keycode for “space” and then keep track of a playerInput.space variable.

 

Introducing The Protagonist Square

 

We now have code for getting player input, but that’s no good without some way to test it. And while I suppose we could just print some logging text to the console that says “Player has pushed right arrow key” it would be much more fun to have some actual graphics moving around the screen.

 

So to start go up to the start of your script to where you declared the playerInput variable and add two new variables for xPos (x position) and yPos (y position). Let’s have them default to 100.

 

var xPos = 100;
var yPos = 100;

 

And now let’s use those variables to draw a red square on our screen by updating our screen drawing function like this:

 

//Draw the screen
function drawScreen(){
   var canvas = document.getElementById('gameCanvas');
   var context = canvas.getContext('2d');

   //Draw background
   context.fillStyle = '#dcdcdc';
   context.fillRect(0,0,600,400);

   //Draw black text
   context.fillStyle = '#000000';
   context.fillText("Loop Count: "+loopCount, 20, 20);

   //Draw a red square the player can control
   context.fillStyle = '#FF0000';
   context.fillRect(xPos, yPos, 50, 50);
}

 

And now we have a little red square that we can move around just by changing xPos and yPos. The logical next step is to use player input to change xPos and yPos, which we can do by rewriting updateGame like this:

 

function updateGame(){
   loopCount++;
   
   if(playerInput.right){
      xPos+=5;
   }

   if(playerInput.left){
      xPos-=5;
   }

   if(playerInput.up){
      yPos-=5;
   }

   if(playerInput.down){
      yPos+=5;
   }
}

 

Give It A Try

 

Save your changes, reload your game page and hit the “Canvas Test” button. You should see a red square appear on the screen, and the red square should move around when you press the arrow keys. If not you have some debugging to do. Make sure you copied the most recent functions correctly and that the playerInput, xPos and yPos variables are all properly declared inside the script tags but before you declare any functions.

 

And with that we’re done for this week. Next week I’ll probably talk about collision detection. Or maybe gravity. But since gravity isn’t really that useful without a ground to collide with I’m thinking it will probably be collision detection.