jQuery Image Block Sliding Game (with source code)

Tutorial: How It Was Made

Making a jQuery Game
__________________________________________________________

Let's get crazy and make an entire game in jQuery.

The goal of today's episode is to look at a simple browser-based game and explain how it was made line by line. I think this is a great way to learn jQuery.

Note, this tutorial doesn't constitute for the absolutely ideal way of writing jQuery code from an advanced programmer's point of view. But this is done on purpose to keep things simple and easy to understand for beginners.

If by the end of this tutorial the code provided here still doesn't seem clear enough 
I recommend grabbing a copy of my jquery tutorial book which contains a multitude of tutorials and visual diagrams that help you study JavaScript and jQuery. It's written in an easy to understand language and contains detailed explanations.

For this tutorial,
We will use a 2D image square-sliding game I created this week and I will go over each line of code to demonstrate the train of thought.

I really do believe that breaking this game up into explanations on 
per-line basis will help you understand how to use jQuery in your own projects.

Let's go ahead and actually create a jQuery plug-in. A plug-in is nothing more than our own custom jQuery method. You know how we have .css() and .animate()? Well, jQuery gives us the ability to extend its own functionality with custom methods that we create ourselves.

We will actually create our own jQuery method and call it .fifteen(); because the game is called Fifteen. Therefore, in order to launch the game inside an HTML element with id "#target" we will call this command:


    // .fifteen() is our custom method we will create:

    $("#target").fifteen(128); 

This will create and attach the game board to the div whose id is "target." Also, each square will become 128 by 128 pixels in width and height based on the only passed parameter.

Executing a custom method this way passes the selector "#target" to our plug-in function. Inside our custom method, we can refer to that selector/element using the this keyword. And we can also enable jQuery methods on it by passing it to the new jQuery object like so: $(this);

In order to create our own jQuery plug-in (we can also refer to this as extending functionality of the jQuery library with our own methods) we will use the $.fn.extend method. Let's take a look:

$.fn.extend(
{
    fifteen: function (square_size)
    {
        // Game code goes here...

        // Example -- set the width of all DIVs to what was passed as square_size

        $("div").css({width: square_size});

        // The basics of the inner-workings of a plug-in:
       
var a = this;                // refers to the passed selector,
                                     // eg: $("#target")
        
var b = $(this);             // same thing, but with jQuery methods enabled

        // Let's do something with the HTML element passed as the CSS selector
       
this.style.color = "red";    // paint all text inside "#target" red
       
$(this).css("color", "red"); // same exact thing, using jQuery method .css()
    }
});

That's it! This is the basic structure of any jQuery plug-in.

Within the scope of the plug-in the this object refers to what was passed in the selector. Also, the square_size parameter is just a custom, arbitrary parameter passed to our game.

We decide what the parameters should be, and if your game or plug-in require more, simply define more parameters, as in:

$.fn.extend( { fifteen: function(square_size, param2, param3, etc) { /*.. game code...*/ } } );

Within the scope of your plug-in you refer to parameters by the very same names.

In my case square_size is the only parameter. It defines the arbitrary size of the square in the game. I use 128 (as in 128 pixels in width and height). The grid is 16 by 16, but there are only 15 movable squares, because one is always empty. However, we still create all 16 DIVs, and just make one white. We do this in order to simulate the shadow effect on an empty square.

Before we get into the code, let's take a look at the game's construction as far as HTML goes. You will notice that there are 16 squares and each square is a separate DIV element:



You can see the game in action on this web page.

The point of the game is to shuffle the image, one square at a time (by shifting it into the empty square, thus swapping locations) until the image is complete.


The white square is always empty. You are only allowed to shift squares that can physically be shifted into the empty spot, as if on a physical game board. This means only squares to the north, south, west and east of the empty square can be shifted.

- - -

Idea 1

Remember that when writing your plug-in it is wise to inject the HTML elements which are created as part of the game... into a parent DIV. The purpose of this is that your plug-in becomes embeddable into any arbitrary HTML element. Different websites have different layouts. So it's important for our plug-in to be flexible. That it could be embedded into an arbitrary HTML element anywhere on the page. In this example I called that element:

    <DIV id = "target"></DIV>

Moving around this element will physically move the game around anywhere on the page.

Idea 2

We leave <div id = "target"></div> unpopulated with any game HTML. Why's that? This is because the plug-in itself will generate game's HTML elements and insert them into the target DIV. This is smart, because it keeps the parent element clean. But also, this example in particular allows us to explore the jQuery's native .append(html) method. It literally appends new HTML at the end of another element. That is, you never even have to write HTML into the document itself, the .append() method injects HTML into the web page dynamically, you just specify the target element using a selector like:

$("#board").append("<div></div>"); // Add one div to the end of #board

Idea 3

I think it's worth mentioning that we can refer to DIVs inside, say, a parent DIV as children. This is really helpful. For example, let's say we have 16 DIVs stored inside one parent DIV:

<div id = "
board">
    <div></div>

    <div></div>
    <div></div>
        <!-- ... ok, imagine 16 DIVs here. These are the "children" of "#board" //-->
    <div></div>
    <div></div>
</div>

You don't really need to assign 16 IDs to all 16 DIVs! jQuery takes care of that for us. For example, to refer to the 3rd DIV inside a parent DIV (in our game it's #board,) instead, we can do something like this without ever assigning any classes or ids to any of the children:


// Hide 3rd DIV in the list of children. No need to assign an id to each one!
$("#board").children("div:nth-child(3)").hide();

Noticewe used the .children() method to grab all children of a parent (DIVs inside parent,) and then we also specified that we need a 3rd child using the literal selector :nth-child(n) where n is the index of the DIV we need. Note, however that this index doesn't start with 0 like JavaScript arrays. It starts with index of 1. :nth-child(0) will not select anything.

Well, enough with the ideas.

I think we are ready to start writing the code. Let's get to it.

<head>
<script type = "text/javascript">

// This is a JavaScript event. It means - once DOM is finished loading,
// execute everything inside the callback function scope

// This is where we initialize the game

$(document).ready(function()
{
    // Initialize the game and create the plug-in

    // When the squares swap places, the moving square must always appear on top
    var zi = 1; // We increment z-index each time a square is shifted

    // The index of the empty square by default, the 16th square
    var EmptySquare = 16;

    // Now, this is where we create the plug-in and call it fifteen.
 
    $.fn.extend({ fifteen:
 
        function(square_size)
        {
            // Grab the id of the HTML element into which we are placing the game,
            // it is the selector - "#target" from  $("#target").fifteen(128);
            var targetElement = "#" + $(this).attr("id"); 
 
            var sqSize = square_size + 'px';
            var boardSize = (square_size * 4) + 'px';

            // Inject DIV into target, this is our game board
            $(targetElement).html("<div id = 'board'></div>"); 

            $("#board").css({ position:'absolute', width: boardSize, height: boardSize, border: '1px solid gray' });

            // Populate the game board's HTML container with 15 squares
            for (var i = 0; i < 16; i++)
            {
                $("#board").append("<div style = 'position: absolute; left: " + ((i % 4) * square_size) + "px; top: " + Math.floor(i / 4) * square_size + "px; width: " + square_size + "px; height: " + square_size + "px; text-align: center; line-height: 128px; -moz-box-shadow: inset 0 0 20px #555555; -webkit-box-shadow: inset 0 0 20px #555555; box-shadow: inset 0 0 20px #555555; background: #ffffff url(monalisa.png) " + (-(i % 4) * square_size) + "px " + -Math.floor(i / 4) * square_size + "px no-repeat !important'></div>");
            }
 
            // Empty up the 16th square, as the starting point
            $("#board").children("div:nth-child(" + EmptySquare + ")").css({backgroundImage: "", background: "#ffffff"});

            // Attach click event to each square
            $("#board").children("div").click(function()
            {
                Move(this, square_size);
            });
        }
    });

    // Move() is the function that is called when a square is clicked
    // Note that it is independent of the plug-in itself which is described above
    // It takes two parameters,
    //     1. object handle to the square that was clicked, and
    //     2. the width of the square
    function Move(clicked_squaresquare_size)
    {
        // We need to locate movable tiles based on where the empty spot is,
        // We can only move the four surrounding squares
        var movable = false;
 
        // Swap x/y between the clicked square and the currently empty square
        var oldx = $("#board").children("div:nth-child(" + EmptySquare + ")").css("left");
        var oldy = $("#board").children("div:nth-child(" + EmptySquare + ")").css("top");

        var newx = $(clicked_square).css("left");
        var newy = $(clicked_square).css("top");
 
        // The clicked square is north of the empty square
        if (oldx == newx && newy == (parseInt(oldy) - square_size) + 'px')
            movable = true;
 
        // The clicked square is south of the empty square
        if (oldx == newx && newy == (parseInt(oldy) + square_size) + 'px')
            movable = true;
 
        // The clicked square is west of the empty square
        if ((parseInt(oldx) - square_size) + 'px' == newx && newy == oldy)
            movable = true;
 
        // The clicked square is east of the empty square
        if ((parseInt(oldx) + square_size) + 'px' == newx && newy == oldy)
            movable = true;
 
        if (movable)
        {
            // Increment zindex so the new tile is always on top of all others
            $(clicked_square).css("z-index", zi++);
 
            // Swap squares... Animate new square into old square position
            $(clicked_square).animate({ left: oldx, top: oldy }, 200, function()
            {
                //Move old square into new square position
                $("#board").children("div:nth-child(" + EmptySquare + ")").css("left", newx);
                $("#board").children("div:nth-child(" + EmptySquare + ")").css("top", newy);
            });
        }
    }

    // Ok, we're ready to initialize the game, let's do it.
    // Create a game with 128 by 128 squares inside "#target" div:

 
    $("#target").fifteen(128); 

});
</script>
</head>
<body>

    <!-- This is where the game will be injected //-->
    <div id = "target"></div>

</body>
</html>

Please see the link to the demo of the game underneath the Mona Lisa picture.

I tried to explain the code to the best of my ability here. 

However if you are still struggling to understand what some of the things mean I recommend grabbing a copy of my jquery tutorial book which contains a multitude of tutorials and visual diagrams to help you really understand JavaScript and jQuery.


I hope you enjoyed this tutorial and perhaps learned a thing or two.

Thanks for reading!


Greg Sidelnikov






$(document).ready() { ... }


HTML


Initialize the Game


You have my permission to use this code in your own projects.

Image Sliding Game - jQuery