Javascript Game Development - Keyboard Input

Arthur Schreiber · 27 February 2011

Now that we have our basic game loop layed out, we can focus on implementing other aspects of our javascript based game. What I want to show in this post is how you process keyboard input.

Keyboard Events

If you’ve done any previous web development with javascript, you’ll most likely know the keydown and keyup events that get fired by the browser when a key is pressed down and released again.

Let’s say we want to create a game where the player controls a small black rectangle and can move it around in a bigger area (very sophisticated, I know!).

First, we’ll need a class that represents our player object:

function Player() {
  this.x = 0;
  this.y = 0;
}

Player.prototype.draw = function(context) {
  context.fillRect(this.x, this.y, 32, 32);
};

Player.prototype.moveLeft = function() {
  this.x -= 1;
};

Player.prototype.moveRight = function() {
  this.x += 1;
};

Player.prototype.moveUp = function() {
  this.y -= 1;
};

Player.prototype.moveRight = function() {
  this.y += 1;
};

Next, we’ll need to hook up on instance of the Player class to our existing game code.

Game.start = function() {
  ...
  
  Game.player = new Player();
  
  ...
};

Game.draw = function() {
  ...
  
  Game.player.draw(Game.context);

  ...
};

Last, we need to setup our event handling code.

window.addEventListener('keydown', function(event) {
  switch (event.keyCode) {
    case 37: // Left
      Game.player.moveLeft();
    break;

    case 38: // Up
      Game.player.moveUp();
    break;

    case 39: // Right
      Game.player.moveRight();
    break;

    case 40: // Down
      Game.player.moveDown();
    break;
  }
}, false);

This first version kinda works, but it is pretty choppy and only ever works for one key. Why?

The choppiness is due to the fact that the keydown event is fired repeatedly with small pauses between each event, and these pauses are not synced up with our game update code. So we’ll have to figure out a way to get them in sync.

The problem that only ever one key is recognized comes from the fact that the browser only ever repeats keydown events for the last key that was pressed.

For working around these two problems, I’m using this super simple helper object:

var Key = {
  _pressed: {},

  LEFT: 37,
  UP: 38,
  RIGHT: 39,
  DOWN: 40,
  
  isDown: function(keyCode) {
    return this._pressed[keyCode];
  },
  
  onKeydown: function(event) {
    this._pressed[event.keyCode] = true;
  },
  
  onKeyup: function(event) {
    delete this._pressed[event.keyCode];
  }
};

You can hook it up to keydown and keyup events like this:

window.addEventListener('keyup', function(event) { Key.onKeyup(event); }, false);
window.addEventListener('keydown', function(event) { Key.onKeydown(event); }, false);

This object tracks the key status of individual keys based on the keydown/keyup events fired by the browser. Using it, we can easily check in our game update code whether a specific key is currently pressed down or not. Now we add the following function to our Player class:

Player.prototype.update = function() {
  if (Key.isDown(Key.UP)) this.moveUp();
  if (Key.isDown(Key.LEFT)) this.moveLeft();
  if (Key.isDown(Key.DOWN)) this.moveDown();
  if (Key.isDown(Key.RIGHT)) this.moveRight();
};

Then we only need to hook this also up to the Game.update method:

Game.update = function() {
  ...
  Game.player.update();
  ...
};

Check out this final version.