Sorasyn   -  Dec 13, 2014

Alright, so I've been working on a Checkers game in my free time using HTML 5 and JS. While I've not made a lot of progress just yet, I have hit somewhat of a brick wall. I'm not all that proficient in JS just yet, but I've done a fair amount of research concerning it, to little avail.

My problem is I can create and load images just fine, but when it comes to drawing them properly onto the canvas is when I get problems. When using drawImage(...); calls outside a loop, they will draw correctly, and more importantly, at the correct coordinates. Conversely, if I were to place a drawImage(...); call inside a loop, the images will display correctly, but at the coordinates of the last image to be drawn.

document.addEventListener('DOMContentLoaded',onLoad,false)

/* Holds information about a game piece on the board */
function onLoad() {
    /* Grab the canvas element & context drawer */
    var canv = document.getElementById("board");
    var ctxt = canv.getContext("2d");

    /*Initialize Board & Game Values*/
    var rows      = 8;
    var cols      = 8;
    var evenTiles = "#CCC";
    var oddTiles  = "#444";
    var board     = [];
    var red       = new Image();
    red.src       = "Images/Red.png";
    var black     = new Image();
    black.src     = "Images/Black.png";

    /* Initialize the underlying array "pieces" to default values */
    for (a = 0; a < rows; a++) {
        row = [];
        for (b = 0; b < cols; b++) {
            if (a < 2) {
                if ((a % 2) == 0)
                    if ((b % 2) != 0)
                        row.push(new Piece(Piece.Color.RED, Piece.Status.NORMAL, b, a));
                    else
                        row.push(null);
                else
                    if ((b % 2) == 0)
                        row.push(new Piece(Piece.Color.RED, Piece.Status.NORMAL, b, a));
                    else
                        row.push(null);
            }
            else if (a > (rows - 3)) {
                if ((a % 2) == 0)
                    if ((b % 2) != 0)
                        row.push(new Piece(Piece.Color.BLACK, Piece.Status.NORMAL, b, a));
                    else
                        row.push(null);
                else
                    if ((b % 2) == 0)
                        row.push(new Piece(Piece.Color.BLACK, Piece.Status.NORMAL, b, a));
                    else
                        row.push(null);
            }
            else
                row.push(null);
        }
        board.push(row);
    }

    /* Draw the game board to the canvas */
    for (a = 0; a < rows; a++) {
        var row = (canv.height / rows) * a;
        for (b = 0; b < cols; b++) {
            var col = (canv.width / cols) * b;

            if ((a % 2) == 0)
                if ((b % 2) == 0)
                    ctxt.fillStyle = evenTiles;
                else
                    ctxt.fillStyle = oddTiles;
            else
                if ((b % 2) == 0)
                    ctxt.fillStyle = oddTiles;
                else
                    ctxt.fillStyle = evenTiles;

            ctxt.fillRect(row, col, (canv.height / rows), (canv.width / cols));

            //# PROBLEMATIC CODE #
            if (board[a][b] != null) {
                var piece = board[a][b];

                if (piece.Color == Piece.Color.RED)
                    red.addEventListener("load", function () { ctxt.drawImage(red, piece.X * 100, piece.Y * 100) }, false);
                else
                    black.addEventListener("load", function () { ctxt.drawImage(black, piece.X * 100, piece.Y * 100) }, false);
            }
            //# END PROBLEMATIC CODE #
        }
    }
}

The above code produces the following which draws all the pieces on top of one another at the last image's coordinates.

result

I'm thinking that the coordinates are changing, before the image is fully drawn, thus prompting the renderer to keep re-drawing it each time the variable changes. However, on the other hand, one would think that it has ample time to fully draw an image before it's called upon a second time.

Any suggestions?

Hawkee  -  Dec 14, 2014

Why not use HTML and CSS for the layout rather than a canvas? It would be far simpler.

Sorasyn  -  Dec 14, 2014

I'd never considered that. It seemed easier to draw it this way as opposed to positioning HTML elements, painstakingly shift the images from square to square, etc.

The for loop I have creating the canvas board is ugly, but it works all the same.

Hawkee  -  Dec 14, 2014

I don't think it would be difficult at all to do it in HTML. You just need black and white DIV classes with fixed widths/heights and coordinate based ID's. The pieces can be CSS classes with centered background images. It would be very easy to move a piece by adding and removing the classes at particular coordinates.

[Plornt]  -  Mar 16, 2015

I suppose its more based on what they'd like to do in the future. Learning to do it with canvas might be better if they're wanting to get more involved with making HTML5 based games.

As for the actual issue at hand, firstly create some sort of loading routine to load the images before the game is started. Then just reuse that image element to draw to the screen. I think the issue is arising from the very very very common mistake when writing callbacks. The load callback is saving a reference to the variable that holds the current peice (which means the piece that is referenced on image load is the next/last one in the loop). If you want to make your current version work wrap it in an IIFE http://benalman.com/news/2010/11/immediately-invoked-function-expression/ with the peice as a parameter.

Sign in to comment

Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.