Making a game from scratch in HTML5

“Pong is one of the earliest arcade video games; it is a tennis sports game featuring simple two-dimensional graphics.” - Wikipedia

Have you ever dreamed of building a game in JavaScript? I did, and I also managed to make my first one. Of course I also wrote some tips and gotchas to help you complete this nice challenge.

How to make Pong in HTML5 canvas

Pong, at it’s core, is an extremely simple game. That’s why it’s a good one to begin with if you have just started learning game design basics. Of course you could start with many other games, but if you are looking for something relatively simple to build, Pong really is one of the simplest games ever made.

AFAIK, there are at least two ways of doing it: I personally call them the “simple way” and the “hard way”. I did both, but first let’s explore the simple one.

Project structure

I aimed to make it as simple as possible, so I just created one HTML file that is referencing few JavaScript files. You may ask, why not a whole single file? Because it’s usually preferable to have many little files rather than one massive plate of spaghetti code. So here’s served the project’s structure:

1
2
3
4
5
6
7
8
index.html
canvas.js
game.js
keyboard.js
main.js
render.js
reset.js
update.js

index.html is our single entry point to the game.

canvas.js contains the code for initializing the canvas DOM object and the 2D context.

game.js contains the game objects. This file will be executed only once at the beginning, when the game loads.

keyboard.js has the keyboard bindings.

main.js is perhaps the most important file, because it contains the main game loop.

render.js does… the rendering. (you don’t say?)

reset.js is for resetting the game to the initial state, called every time a player wins.

update.js contains 90% of the game logic, and obviously is for updating the game state (before rendering).

The main loop

The main loop is at the core of our game. Maybe it’s hard to believe, but virtually every single videogame in the world lives and dies within a loop.

Implementing a game loop is a lot simpler than you think, but it’s not the focus of this tutorial. The resource I highly recommend for getting started is How to make a simple HTML5 Canvas game, by Matt Hackett. All my work is actually based on his tutorial. Read it, and you’ll get a basic understanding of the fundamentals of game development.

We want to focus on the game logic now, so for the time being let’s pretend our game loop looks like this:

1
2
3
4
while (true) {
  update(); // update game objects
  render(); // render game objects
}

Got it? :-)

Ball movement

How do we make the ball moving across the screen? In JavaScript, we can define objects with properties. The essential properties of our ball object are position and speed. The position represents the coordinates where the object is in the canvas space. Example:

1
2
3
4
5
6
var ball = {
  x: 0,
  y: 0,
  speedX: 0
  speedY: 0
}

In order to make it move, we should change its position, and we can do it through the speed. This is the heart of our game:

1
2
3
4
5
if (isGameStarted) {
  // Ball movement
  ball.x += ball.speedX * modifier;
  ball.y += ball.speedY * modifier;
}

As you can imagine, isGameStarted is just a boolean flag. But what’s modifier? Well, it’s the delta time of our game loop. Put simply, the delta time is the time elapsed between a frame and another. This is very useful because we can use it to calculate how fast the ball should move. Without it, the game would just lag all the time.

Ball bounce

The game logic is mainly about the ball: it should be able to bounce away from the paddles. How can you implement that? It’s pretty simple - have a look at the code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  // Ball is out of the left boundary
  if (ball.x <= 0) {
    // Player 2 wins!
    p2.score++;
    reset(); // reset the game to the initial state
  }

  // Ball is out of the right boundary
  if (ball.x >= canvas.width - ball.size) {
    // Player 1 wins!
    p1.score++;
    reset();
  }

  // Ball is colliding with the top
  if (ball.y <= 0) {
    ball.speedY = Math.abs(ball.speedY);
  }

  // Ball is colliding with the bottom
  if (ball.y + ball.size >= canvas.height) {
    ball.speedY = Math.abs(ball.speedY) * -1; // inverted
  }

Can you see what’s going on in the code? Basically, if the ball goes beyond the canvas’ left or right boundaries, all we do is increment the score and reset the game. If the ball touches the top or the bottom instead, we invert its speed on the Y axis. If you think about it, it’s all you need to make something reflect over a surface. So, in other words, if the speed is negative we make it positive, and viceversa.

Collision detection

What should happen when the ball touches one of the paddles? Fundamentally the same thing explained above: it should bounce away, reflecting on the paddle’s surface (and to do this we invert the Y speed). But how do we actually check if they are colliding?

The most common kind of collision detection is called AABB - Axis-Aligned Bounding Boxes. You can find plenty of resources around the Web explaining how this technique works, so I won’t talk about it (have a quick search for “AABB collision detection”, or just keep reading). As Linus Torvalds once said,

“Talk is cheap. Show me the code.”

Here we go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (
  ball.x <= (p1.x + p1.width)
  && p1.x <= (ball.x + ball.size)
  && ball.y <= (p1.y + p1.height)
  && p1.y <= (ball.y + ball.size)
) {
  // Ball is colliding with the left paddle
  // Ensure the speed on the X axis is positive
  ball.speedX = Math.abs(ball.speedX);

  // Give the ball a bit of randomness by 
  // increasing/decreasing its speed on the Y axis
  ball.speedY = randomize();
}

The logic for the right paddle is exactly the same, but the speed on the X axis should be negative instead. In my case I also added a randomize() function, so the game will be more interesting - you don’t have to implement it this way, but a bit of randomness never hurts in gaming!

1
2
3
4
5
6
function randomize() {
  // Random float between 0 and 999.9
  var _rand = Math.random() * 1000;
  // positive or negative?
  return Math.random() > 0.5 ? _rand : _rand * -1;
}

Paddle movement

We move the paddles with the keyboard. Keyboard controls can be handled simply by keeping track of which key is currently being pressed (watch for the keydown event). We can use a simple JavaScript object for that (or an array if you prefer):

1
2
3
4
5
6
7
8
9
10
// Handle keyboard controls
var keysDown = {};

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

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

The keyup and keydown events are the only two we need for handling the whole keyboard. So on keydown we add the key; on keyup we remove it. Simple.

Of course we are going to need JavaScript objects for the paddles as well. In my game I called them p1 and p2, which can be interpreted as players too.

Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Update game objects
var update = function (modifier) {
  if (87 in keysDown) { // P1 holding up (key: w)
    p1.y -= p1.speed * modifier;
  }

  if (83 in keysDown) { // P1 holding down (key: s)
    p1.y += p1.speed * modifier;
  }

  if (38 in keysDown) { // P2 holding up (key: arrow up)
    p2.y -= p2.speed * modifier;
  }

  if (40 in keysDown) { // P2 holding down (key: arrow down)
    p2.y += p2.speed * modifier;
  }
}

Rendering the objects in the canvas

Here’s the render() function, in all its glory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var render = function () {

  ctx.fillStyle = "#0F0"; // green

  // P1
  ctx.fillRect(p1.x, p1.y, p1.width, p1.height);

  // P2
  ctx.fillRect(p2.x, p2.y, p2.width, p2.height);

  // ball
  ctx.fillRect(ball.x, ball.y, ball.size, ball.size);

  // Text options
  ctx.fillStyle = "rgb(250, 250, 250)";
  ctx.font = "18px Helvetica";
  ctx.textAlign = "left";
  ctx.textBaseline = "top";

  // P1 Score
  ctx.fillText(p1.score, 32, 32);

  // P2 Score
  ctx.fillText(p2.score, canvas.width - 32, 32);
};

It’s probably worth mentioning that you can use JSON.stringify() to debug your objects directly in the canvas, e.g.:

1
2
// Debugging the ball object
ctx.fillText("ball: " + JSON.stringify(ball), 0, 0);

However, I don’t recommend it. Just use whatever your browser is offering! If you are a web developer you surely know that there’s a built-in JavaScript console for debugging in your browser (if you don’t, search for developer tools).

Resetting the game

We need to reset the game every time a player scores. The logic is very simple, we just need to provide default values for our objects. Example below.

1
2
3
4
5
6
7
8
9
10
11
// Reset the game
var reset = function () {

  isGameStarted = false;

  ball.x = (canvas.width - ball.size) / 2;
  ball.y = (canvas.height - ball.size) / 2;

  ball.speedX = randomize(); // randomly start going left or right
  ball.speedY = 0;
}

This is the main logic of Pong. However, it’s not perfect, and it could be improved a lot in several ways… for example by implementing physics rules (or by using a physics engine, that has already done the job for us). We have just simulated the reflection of a ball on a surface, but it’s not realistic at all - let’s make it better.

The “hard way”

In a proper Pong game, you can usually control where the ball goes. It could have a steeper or shallower angle of reflection, based on where the ball landed. Should it land on one of the edges of the paddle, the collision should be inelastic. In case it lands exactly on the middle of the paddle, the collision should be totally elastic.

In order to implement physics rules in a game, you should have an understanding of basic vector math, trigonometry and - of course - physics. But don’t fear, you don’t have to know everything: just the basics. I personally didn’t know much about physics, but I learned it by reading about it.

Here are some useful resources on the Web:

Let’s explore together the potential of 2D vectors.

Using 2D Vectors

The main thing you’ll have to understand is how vectors are used in game development. As an example, let’s go back to our ball object and modify it to use vectors. It will look like this:

1
2
3
4
var ball = {
  position: new Vector({ x: 0 , y: 0 }),
  velocity: new Vector({ x: 0 , y: 0 })
}

Four values at the price of two attributes! And this is a lot better now, not only because we are using less attributes, but because we can use vector math. Believe me, vectors simplify your game a lot.

You may have noticed that I didn’t use speed, but I used velocity instead. The reason is that speed is a scalar quantity, while velocity is a vector quantity. Put simply, speed is an information that’s contained in velocity! You may want to read about it, albeit not directly related to programming.

A proper ball reflection

We can implement proper reflection (not a fake one) by using this JavaScript function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var ball = {
  // the velocity vector
  velocity: new Vector(),

  /*
  * The formula:
  * 
  *  R = 2(V · N) * N - V
  *
  * V: velocity vector
  * N: a normalized vector of the plane surface (e.g. paddle or wall)
  * R: the reflected velocity vector
  */
  deflect: function (N) {
    var dot = this.velocity.dot(N);
    var v1 = N.multiplyScalar(2 * dot);
    this.velocity = v1.subSelf(this.velocity);
  }
}

This is how I’ve implemented it by using a vector library I found on the Web (find the source code on GitHub). Given a paddle’s normal, it will reflect any vector, but you have to make sure the paddle’s normal is a unit vector (in other words, it’s normalized).

Conclusion

I hope you enjoyed this article. Who’s following my blog since the beginning will probably remember my first blog post. It was more than 2 years ago, and at that time I was really excited by the idea to build a game with JavaScript. I finally did it, and it has been fun indeed! However, I learned a big lesson: although it was fun, it wasn’t really worth reinventing the wheel. So, if you got through all this tutorial, first of all congratulations! Secondly, consider using a game engine. Thirdly, maybe consider not using JavaScript… just use whatever you feel comfortable with. For instance, if you like the Ruby language (I do!) you could use Opal, a Ruby to JavaScript compiler.

Demo and source code

You can play the game here.

The full source code is on GitHub so you can clone it, fork it and even make your own from scratch, if you feel like it’s worth your time. If you are interested in the simple way, checkout the v1.0 release. The hard way is in the master branch.

As always, if you have any thoughts or questions, feel free to leave a comment below.

Have fun!

Install Sublime Text 3 on Linux

There are many ways of installing Sublime Text 3 on Linux, but if you’re looking for a fast, straightforward way, I believe you are in the right place.

This script will install the latest build of Sublime Text 3, released on 29 August 2014 (build 3065).

Open up your terminal and run this:

1
curl -L git.io/sublimetext | sh

It will install the Package Control as well, so you don’t have to do it yourself.

If you are interested to see the actual code behind, here we go:

https://gist.github.com/simonewebdesign/8507139

It should work on most Linux distros; if not, please let me know by leaving a comment below. I’m here to help.

Enjoy!

How to change Bootstrap grid to 960px

Many people think that changing .container’s width to 960px is sufficient; well, it’s not quite true.

As per Bootstrap’s docs, you can disable responsiveness by forcing a fixed width to the container:

1
2
3
.container {
  width: 960px !important;
}

But is it what you really want?

I love Bootstrap, but personally if I had to build a fixed-width 960px site, which is quite old school nowadays, I wouldn’t use Bootstrap at all. And you know what? In most cases I wouldn’t even use a grid system! I’d use plain-old CSS (or Sass), and I’m pretty confident it would be fine. But that’s me. Of course you are free to do anything you want. But remember, Bootstrap’s focus is on mobile and responsive design.

If you need a 960px grid system, you may not want all the stuff that comes with Bootstrap. Also, you may want to think again about what you are going to build; this is way more important than the front end framework you will choose.

Now, this tutorial is for who wants a 960px site, but still preserving responsiveness.

Show me the light!

What I’m going to explain is not a hack, it’s the way Bootstrap works.

When you need to change Bootstrap’s default width, the best way is to recompile its source code. Yeah, that sounds hard and time consuming, but don’t panic.

If you are using Sass or LESS will be very easy to customize the grid system. However it really depends on what framework you are using.

E.g.: if you are using Ruby on Rails, chances are you are using the bootstrap-sass gem. On the README in GitHub there’s already everything you need to know in order to customize Bootstrap. The only thing you have to be aware is that you should redefine variables before importing Bootstrap, otherwise Bootstrap will use the old ones.

The 960px grid system values

These are the correct values for a 960px grid (in Sass):

1
2
3
4
5
// default is 1140px + $grid-gutter-width
$container-large-desktop: 940px + $grid-gutter-width;

// default is 30px
$grid-gutter-width: 20px;

What about the media queries?

You may want to disable the media query for large desktops, you don’t need it anymore.

Changing $screen-lg to be $screen-md should do it.


I believe this is the best solution so far. It’s far better than removing all stuff related to large desktops, because:

  • it’s definitely easier;
  • you’ll be able to upgrade your custom Bootstrap when you’ll want to;
  • you won’t run into any issues.

What if I’m using plain CSS?

If you are using CSS you can use the online build customizer. However I recommend you to switch to Sass or LESS.

3 simple steps

  1. Go to: http://getbootstrap.com/customize/
  2. Customize the Grid system’s variables;
  3. Download your custom version of Bootstrap.

That’s it!

Getting started with rbenv

If you are struggling to get rbenv working on your machine, then I believe you landed in the right place: here I’m sharing some gotchas I had while setting up rbenv on Mac OS X 10.9.3.

First of all, make sure you remove RVM completely. It’s not compatible with rbenv.

1
$ rm -r ~/.rvm

Remove it from your $PATH as well.

I’m using fish shell, that has its own quirks, such as it doesn’t have a export command to export variables to $PATH. Instead it uses set. E.g.:

1
$ set VARIABLE VALUE

For example, in order to call rbenv, I set up my $PATH this way:

1
$ set -u fish_user_paths $fish_user_paths ~/.rbenv/bin

Fish also handles things a bit differently. If you are using it, you’ll probably be burned by the fact it doesn’t understand the $ function that in POSIX shells creates a sub shell. Fortunately I managed to find a fix for that: see this article. Basically it says you need to add this code to your config.fish file:

1
2
set -gx RBENV_ROOT /usr/local/var/rbenv
. (rbenv init -|psub)

But pay attention and make sure you understand what’s going on here. Actually the code above didn’t work for me, as the installation path of my rbenv was different. If you installed rbenv with git clone, the right code is:

1
2
set -gx RBENV_ROOT ~/.rbenv
. (rbenv init -|psub)

In fish it’s also possible (albeit not recommended) to use the config.fish file in order to set the $PATH variable permanently. You can do it with (e.g.):

1
set -x PATH ~/.rbenv/shims /usr/local/bin /usr/bin /bin $PATH

A big gotcha here is to have ~/.rbenv/shims before /bin and /usr/bin, otherwise the shell will load the system’s Ruby first (and you don’t want to use the system’s Ruby for your projects).

To ensure I was using the right Ruby version, I moved the system Ruby away, in /tmp. Of course you need to sudo for that:

1
$ sudo mv /usr/bin/ruby /tmp

Another super important thing is: NEVER EVER install gems using sudo. If you do that you’re going to have serious problems/conflicts and weird errors in your shell. Do yourself a favour by installing things in your home (~) and avoiding sudo at all costs. Always.

A good thing to do for ensuring you are going down the right path is to use which: which rbenv, which ruby and which gem will tell you if you actually have your stuff in the right place (that is the .rbenv/shims on your home folder).

At this stage you may be able to install Ruby (you need the ruby-build plugin for that). Run:

1
$ rbenv install -l

The command above will give you a list of all the available rubies to install. Run, for example:

1
2
$ rbenv install 2.1.2
$ rbenv rehash

The above will install Ruby 2.1.2 into ~/.rbenv/versions and will rebuild your shim files. Note that you need to run rbenv rehash every time after you install a version of Ruby.

Another useful command is:

1
$ rbenv global

This tells you which version of Ruby you have. It may differ from what ruby -v says to you, and if that’s your case, you’ll probably want to check your $PATH.

Hopefully that’s enough for getting you started with rbenv. Enjoy!

Bye bye Wordpress. Welcome Octopress!

Octopress

I did it! I’ve finally migrated my blog to Octopress. It was a bit of a PITA, and it took a lot more than what I expected, but I did it.

Apologies if you weren’t able to see the website yesterday; the DNS took about 11 hours to propagate, and the site was back UP just this morning. It is now hosted by Heroku and it’s faster than ever.

Prepare yourself to see lots of new stuff in the next few weeks! ;-)