Somehow I find myself being madly in love with HTML5 game development lately. After reading some introductory books I was ready to get my hands dirty and coded my own little Pong clone. I am an absolute beginner but as soon as the ball and the paddles moved I felt pretty good about myself. So good that I opted for polishing my backend code using idiomatic JavaScript “Pain in the ass” object orientation.

Note: If you are only here for a refreshing round of Pong with your buddy, feel free to skip the article and go nuts.

JavaScript Object Orientation 101

Let’s dive right in and have a look at this little code snippet:

function Game(name) {
  this.player = name;
}
Game.prototype.start = function() {
  this.gameloop();
}
Game.prototype.gameloop = function() {
  console.log(this.player);
};

var g = new Game("Stephan");
g.start();

This is basically the way how you create and instantiate a new class in vanilla JavaScript. We declare a so-called constructor function (or in short: constructor) in the first three lines (it is common practice to capitalize the function name to distinguish it from a normal function) and use it to create an object with the new keyword. The constructor is responsible for three things during the object creation phase:

  1. Obviously, create a new object in memory.
  2. Bind the newly created object to the keyword this (that’s why we can declare new members, like player inside the constructor)
  3. Set the prototype of the new object to the prototype of the constructor (so we can add new methods for all instances by adding functions to Game.prototype)

It’s the Little Things

So far, so good. Now, I don’t like that everybody can access all the methods and attributes of my instances. E.g., it is absolutely possible to write something like g.player = "Max". That bothers me and I started to look for a way to emulate private members.

My first attempt looked like this:

function Game(name) {
  player = name;
}
Game.prototype.start = function() {
  this.gameloop();
}
Game.prototype.gameloop = function() {
  console.log(player);
};

var g = new Game("Stephan");
g.start();

The member player was not accessible from the outside anymore (g.player will return an undefined) and it still worked as expected. But then it hit me: I created a global variable. That’s what happens if you forget the little var keyword inside functions. Consequently, writing console.log(player) at the end of the code will happily return "Stephan".

Privacy and Privileges

Well, that was the opposite of what I had in mind. So I went on to fix this immediately. It couldn’t be so hard, right?

After a bit of Google research I stumbled upon an article on Private Members in JavaScript. The author states that one can emulate private members by adding normal variable declarations to the constructor. The pitfall here is, that private members are only accessible through private methods.

Perfect, I thought. The method gameloop was supposed to be private anyway. But wait, what about start? This method is our hook to the main game mechanics and it should be possible to invoke it from the outside. At the same time, it has to call the main (private) game loop. Fortunately, JavaScript provides us with a concept called privileged methods.

These are declared with the this keyword inside the constructor and allowed to reference private members:

function Game(name) {
  var player = name;
  var gameloop = function() {
    console.log(player);
  }
  this.start = function() {
    gameloop();
  }
}

var g = new Game("Stephan");
g.start();

That was exactly what I wanted! Encouraged by the latest success I went on to extend my game and add a real game loop and a public score:

function Game(name) {
  var player = name;
  this.score = 0;

  var gameloop = function() {
    console.log(player);
    console.log(score);
  }
  this.start = function() {
    setInterval(gameloop, 2000);
  }
}

var g = new Game("Stephan");
g.start();

After running the code I was amazed how setInterval took care of calling the game loop every 2 seconds. But you can maybe imagine my disappointment when I looked at the line where I expected the score.

When in Doubt, Have a Reference to Your Object

I found myself facing a nasty undefined. Damn! But the explanation is both simple and reasonable. The moment we consign our gameloop method to the care of setInterval we also accept it not being invoked inside the Game context anymore. From then on our timed function is called inside the global object Window. And guess what! That also implies that this is not bound to our game object anymore, but rather to the global object. The global object, however, has no idea of the existence of a attribute called score.

But we are lucky enough to fix this in a second by maintaining a self reference inside our object:

function Game(name) {
  var self = this;
  var player = name;
  this.score = 0;

  var gameloop = function() {
    console.log(player);
    console.log(self.score);
  }
  this.start = function() {
    setInterval(gameloop, 2000);
  }
}

var g = new Game("Stephan");
g.start();

Now that we have a reference to our own object everything works like a charm. But wait, what? How is that even possible? And speaking of “what?”… How can JavaScript know about player in the first place?

Closure is Sexy

That’s what I was thinking. It is important to know that JavaScript has something called lexical scoping. Among other things, that means, JavaScript functions are executed using the scope (which is basically a collection of variable bindings) that was in effect when they were defined, not when they are invoked.

This combination of a function and an associated scope is called closure in computer science. Wherever gameloop is executed, it will always be able to resolve player and self by looking them up in its corresponding scope.

The Actual Game

Oh right! In the beginning, it was all about HTML5 game development. Well, I wouldn’t disappoint you for the world, so here you go! Note: It’s a 2-player game, use the W/S and up/down keys. Also, it’s really bad. But hey… it’s a start.