User Interaction

In this lesson, you will learn techniques for handling user interaction in HTML Canvas-based games.

Applications written for HTML5 Canvas offer no special features to handle user input. Essentially, HTML user input involves using the event-handling system built into browsers.

Keyboard events

We are using the arrow keys to move and rotate the pieces. For this to work, we need to listen for and handle keyboard events. We can listen for the keydown, keyup, or keypress events at the document level. Let’s add an event listener for the keydown event to our document with the addEventListener() method:

document.addEventListener('keydown', event => {
  // Handle event
});

When we are done, we can’t forget to remove the event listener with the removeEventListener() method. Otherwise, we might add multiple listeners and start moving at warp speed.

Enums

Next, we map the keycodes to names we can understand in constants.js. For this, it would be nice to have an enum.

Enum (enumeration) is a special type used to define collections of constants.

There are no built-in enums in JavaScript, so let’s make one by creating an object with the values:

// constants.js
const KEY = {  
  LEFT: 37,
  UP: 38,
  RIGHT: 39,  
  DOWN: 40  
}

Object.freeze(KEY);

const can be a bit misleading when working with objects and arrays, and it does not actually make them immutable. To achieve this, we can use Object.freeze(). Here are a couple of gotchas to look out for:

  • For this to work properly, we need to use strict mode.
  • This only works one level down. In other words, if we have an array or object inside our object, this will not freeze them.

Move pieces

Now that we have the keyboard event registered and the keys mapped, we can start working on the logic of what will happen when we press different keys.

We can start by adding a move() method to the piece class. It takes a piece p as input and updates the x or y variable of the current piece to change its position on the board:

// piece.js
move(p) {  
  this.x = p.x;  
  this.y = p.y;
}

This is simple enough, but now we need to calculate the input to the method. There are many ways of doing this, but keeping the code modern, we will use some new JavaScript features.

Calculate the new position

To begin, we need to calculate the new position of piece depending on which key we press:

  • left: we move p.x - 1
  • right: we move p.x + 1
  • down: we move p.y - 1

To get the new state from the changed coordinates, we can use the spread operator:

(p) => ({ ...p, x: p.x - 1 })

This arrow function spreads the old coordinates to a new object. At the same time, it changes the x coordinate to return the new position.

Object literal lookups

We can use an object for lookup purposes to match keycodes to expressions and get values from object properties…

We can create a lookup object to match the key codes to the state-changing functions. This allows us to send the keycode and current piece to the object and return the piece with the new coordinates.

Piece moves[keyCode](piece)

Because we are mapping the key codes in our enum, we need to calculate them when we do our lookup. This is our next challenge.

Luckily, ES6 allows property keys of object literals to use expressions, making them computed property keys. So, the property key looks like this:

[KEY.LEFT]: expression

With all in place, we can finally code our lookup object:

// main.js
const moves = {
  [KEY.LEFT]:  (p) => ({ ...p, x: p.x - 1 }),  
  [KEY.RIGHT]: (p) => ({ ...p, x: p.x + 1 }),  
  [KEY.DOWN]:  (p) => ({ ...p, y: p.y + 1 })  
};

To use this object literal, we match the keycode and send in the current piece:

let newPosition = moves[keyCode](oldPosition);

Then, we get a new position!

Prevent browser behaviors

In a computer game, you don’t want default browser behaviors interfering with your actions. For instance, you don’t want a press of an arrow key to move the page up and down.

In all event handlers, add a preventDefault() line and return false from the function to prevent both the default action and event bubbling from occurring.

Get hands-on with 1200+ tech skills courses.