Making a Bejeweled Clone using HTML, CSS 3 Animations and JavaScript

December 18, 2011


In case you didn't know, last week PopCap launched a WebGL-powered version of its famous game, Bejeweled (click here to play it). The port looks and works exactly like the original game as well, which is pretty nice. However, there are two problems with using WebGL that they could have avoided by using the approach that we'll be using in this article. First, is that the game doesn't work in Internet Explorer (as IE doesn't support WebGL) and second, is that obviously the game won't work on mobile devices.

When I wrote my "Let's make a Snake Game" article I stated that many 2D games can be solved by using a two-dimensional matrix, and Bejeweled is not the exception. If you really think about it, Bejeweled is just an 8x8 matrix filled with different indexes (numbers). The objective of the game is to align 3 or more rows or columns with the same index. When a row or a column of indexes is deleted, new indexes are added to the matrix to fill the empty places as seen in this GIF, and here's a visual representation of how the matrix looks like, which will give you a better idea of how it works:

Bejeweled Matrix

However, you will notice that the initial grid is not completely random and instead have some pecularities in the initial matrix generation algorithm that equally distributes indexes always considering that at least one or more moves are possible. which is why (if you pay attention) you'll notice the emergence of some of the following patterns:

Bejeweled Patterns


You'll also notice that you won't find groups of 3 or more elements with the same index anywhere on the matrix. While replicating the exact same algorithm used by PopCap in Bejeweled is outside the scope of this article, we can get a pretty decent replica by generating the matrix in three steps (the matrix is just 8x8, so performance efficiency is not a concern, really, besides... i'm trying to keep this simple).

The first pass will traverse the matrix column by column, starting on the first row (from the top left to the bottom right) generating a random index number between 0 and 6. If, while traversing the columns, we find that the current position minus 1, and the current position minus 2 are equal to the current random number, we'll assign that number to the current position plus 1, and generate a new random number to place in the current position instead (that of course, has to be different from the one we have right now).

Once we get to the bottom row and the last column, we'll start the second pass in which we'll start traversing the matrix top, down from left to right, just like we did in the first step. The objective of this pass is to avoid having groups of three or more elements aligned vertically. In case that we do find one, if we're located on a column index equal or less than 3, we'll move elements to the right. If our column index is greater than 3, we'll move elements to the left.

The last and final pass will be executing our index matching function, which we'll also use when the user makes a move.