---
title: Pong Clone In JavaScript
teaser:
tags: web,javascript
author: Matt Mongeau
published_on: 2013-08-17
---

The ability to create interactive games in JavaScript is getting easier with
the constant improvements to JavaScript engines and the ability for browsers to
utilize the GPU. To demonstrate how easy it is to write games in JavaScript
we're going to write a pong clone.

# Getting Started

To write our Pong clone, we'll be using pure JavaScript and we'll be utilizing
the [canvas
element](http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element)
in order to render our game.

Let's create a very simple html page:

    <html>
      <head>
        <script src="pong.js"></script>
      </head>
      <body></body>
    </html>

We'll start our pong.js file by getting the correct `requestAnimationFrame`
invocation:

    var animate = window.requestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      function(callback) { window.setTimeout(callback, 1000/60) };

The [requestAnimationFrame
method](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame)
is extremely useful. It functions a lot like `setTimeout` in that it will call
your callback at approximate 60 calls per second (read: 60fps). What makes it
better than just using `setTimeout` is that your browser can perform
optimizations on the call. For instance, if the tab isn't active it will stop
making calls until it becomes active again.

In order to perform rendering we'll need to setup a canvas and grab its [2d
context](http://www.whatwg.org/specs/web-apps/current-work/#dom-canvas-getcontext):

    var canvas = document.createElement('canvas');
    var width = 400;
    var height = 600;
    canvas.width = width;
    canvas.height = height;
    var context = canvas.getContext('2d');

Now when the page loads we'll attach the canvas to the screen and call a `step`
function using our `animate` method:

    window.onload = function() {
      document.body.appendChild(canvas);
      animate(step);
    };

The `step` function will be responsible for doing three things. First it will
update all of our objects: the player's paddle, the computer's paddle, and the
ball. Next it will render those objects. And lastly, it will use
`requestAnimationFrame` to call the `step` function again:

    var step = function() {
      update();
      render();
      animate(step);
    };

To get something on the screen let's implement `update` as a no-op and for our
render function we'll set the background of our game to `#FF00FF` by using the
[fillStyle](http://www.whatwg.org/specs/web-apps/current-work/#fill-and-stroke-styles)
and
[fillRect](http://www.whatwg.org/specs/web-apps/current-work/#drawing-rectangles-to-the-bitmap)
methods provided by the context:

    var update = function() {
    };

    var render = function() {
      context.fillStyle = "#FF00FF";
      context.fillRect(0, 0, width, height);
    };

When we load up our page, we should see something like this:

![''](http://media.tumblr.com/ae3d825dcd7f77bf414a9319d9fe8770/tumblr_inline_mr9qt1HqOf1qz4rgp.png)

# Adding Paddles and the Ball

Let's add our objects so we can render them to the screen. We'll create our
paddle and give it an x,y position, a width and height, and both an x and a y
speed (which we will use later).

    function Paddle(x, y, width, height) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
      this.x_speed = 0;
      this.y_speed = 0;
    }

    Paddle.prototype.render = function() {
      context.fillStyle = "#0000FF";
      context.fillRect(this.x, this.y, this.width, this.height);
    };

Since each paddle will be controlled independently, one by the player and one
by the computer AI, let's create objects to represent them. The x and y
coordinates are chosen to put the player at the bottom (the canvas's coordinate
system's origin is in the upper left hand corner) and the computer at the top.

    function Player() {
       this.paddle = new Paddle(175, 580, 50, 10);
    }

    function Computer() {
      this.paddle = new Paddle(175, 10, 50, 10);
    }

When we render either the player or the computer, we'll just render their
paddles (in the future we could extend this to render their scores as well):

    Player.prototype.render = function() {
      this.paddle.render();
    };

    Computer.prototype.render = function() {
      this.paddle.render();
    };

The last object we need to create is the ball. Since the ball will be a circle,
the x,y coordinates will represent the center of the circle and we'll give it a
radius of 5:

    function Ball(x, y) {
      this.x = x;
      this.y = y;
      this.x_speed = 0;
      this.y_speed = 3;
      this.radius = 5;
    }

    Ball.prototype.render = function() {
      context.beginPath();
      context.arc(this.x, this.y, this.radius, 2 * Math.PI, false);
      context.fillStyle = "#000000";
      context.fill();
    };

Now we'll build our objects and update our `render` function:

    var player = new Player();
    var computer = new Computer();
    var ball = new Ball(200, 300);

    var render = function() {
      context.fillStyle = "#FF00FF";
      context.fillRect(0, 0, width, height);
      player.render();
      computer.render();
      ball.render();
    };

When we reload the page we should see this:

![''](http://media.tumblr.com/ee51d9f0ca54124ede9461d44f094922/tumblr_inline_mr9rkur6vo1qz4rgp.png)

# Animating

Let's start adding movement. We'll animate the ball so it heads towards the
player's paddle. We'll do this by changing the `update` from a no-op and adding
an `update` method to the ball:

    var update = function() {
      ball.update();
    };

    Ball.prototype.update = function() {
      this.x += this.x_speed;
      this.y += this.y_speed;
    };

The result should look something like:

![''](http://media.tumblr.com/e1302307a5197fefc1f8e51bfbb1dfa1/tumblr_inline_mr9svqDYKJ1qz4rgp.gif)

Since the paddles are stationary we can make the ball bounce back and forth
between them by modifying our update and check to see if the ball hits the left
and right hand sides or the top and bottom. We'll also need to pass both of the
paddles into the update method:

    var update = function() {
      ball.update(player.paddle, computer.paddle);
    };

    Ball.prototype.update = function(paddle1, paddle2) {
      this.x += this.x_speed;
      this.y += this.y_speed;
      var top_x = this.x - 5;
      var top_y = this.y - 5;
      var bottom_x = this.x + 5;
      var bottom_y = this.y + 5;

      if(this.x - 5 < 0) { // hitting the left wall
        this.x = 5;
        this.x_speed = -this.x_speed;
      } else if(this.x + 5 > 400) { // hitting the right wall
        this.x = 395;
        this.x_speed = -this.x_speed;
      }

      if(this.y < 0 || this.y > 600) { // a point was scored
        this.x_speed = 0;
        this.y_speed = 3;
        this.x = 200;
        this.y = 300;
      }

      if(top_y > 300) {
        if(top_y < (paddle1.y + paddle1.height) && bottom_y > paddle1.y && top_x < (paddle1.x + paddle1.width) && bottom_x > paddle1.x) {
          // hit the player's paddle
          this.y_speed = -3;
          this.x_speed += (paddle1.x_speed / 2);
          this.y += this.y_speed;
        }
      } else {
        if(top_y < (paddle2.y + paddle2.height) && bottom_y > paddle2.y && top_x < (paddle2.x + paddle2.width) && bottom_x > paddle2.x) {
          // hit the computer's paddle
          this.y_speed = 3;
          this.x_speed += (paddle2.x_speed / 2);
          this.y += this.y_speed;
        }
      }
    };

The collision detection happening here is pretty standard [Axis Aligned
Bounding
Boxes](http://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box)
or AABBs. You'll notice in the code that if the paddle is moving when it hits
the ball, the `x_speed` is added to the ball. This will cause it to move faster
or slower depending on the direction of the ball and the direction of the
paddle.

# Controls

Now we're going to add in controls so that the player can update the position
of their paddle, we'll do this by adding a `keysDown` object to keep track of
which key is pressed:

    var keysDown = {};

    window.addEventListener("keydown", function(event) {
      keysDown[event.keyCode] = true;
    });

    window.addEventListener("keyup", function(event) {
      delete keysDown[event.keyCode];
    });

The update method of the player can now update the position of its paddle depending on which key was pressed:

    var update = function() {
      player.update();
      ball.update(player.paddle, computer.paddle);
    };

    Player.prototype.update = function() {
      for(var key in keysDown) {
        var value = Number(key);
        if(value == 37) { // left arrow
          this.paddle.move(-4, 0);
        } else if (value == 39) { // right arrow
          this.paddle.move(4, 0);
        } else {
          this.paddle.move(0, 0);
        }
      }
    };

    Paddle.prototype.move = function(x, y) {
      this.x += x;
      this.y += y;
      this.x_speed = x;
      this.y_speed = y;
      if(this.x < 0) { // all the way to the left
        this.x = 0;
        this.x_speed = 0;
      } else if (this.x + this.width > 400) { // all the way to the right
        this.x = 400 - this.width;
        this.x_speed = 0;
      }
    }

# Computer AI

Now we can control our paddle and the ball will bounce around accordingly;
however, the computer is not very good at the game yet so we'll need to add a
very simple AI. For this project the computer will just try its best to
position itself according to the center of the ball. We'll give the computer
player a max speed so that we can occasionally score a point. We'll need to
alter the main `update` function as well as  update the computer player:

    var update = function() {
      player.update();
      computer.update(ball);
      ball.update(player.paddle, computer.paddle);
    };

    Computer.prototype.update = function(ball) {
      var x_pos = ball.x;
      var diff = -((this.paddle.x + (this.paddle.width / 2)) - x_pos);
      if(diff < 0 && diff < -4) { // max speed left
        diff = -5;
      } else if(diff > 0 && diff > 4) { // max speed right
        diff = 5;
      }
      this.paddle.move(diff, 0);
      if(this.paddle.x < 0) {
        this.paddle.x = 0;
      } else if (this.paddle.x + this.paddle.width > 400) {
        this.paddle.x = 400 - this.paddle.width;
      }
    };

And we're done! We have a working pong clone. To see the code in action you can
take a look at [this jsfiddle](http://jsfiddle.net/kHJr6/2/).

As browsers keep getting more powerful, gaming on the web without Adobe Flash
will grow quickly. It's possible that JavaScript will be able to place itself
as one of the most accessible and easily learnable languages to create games
in.
