6
\$\begingroup\$

I'm learining JS. I have prepared a simple color flooding game, like Pixelated.

The engine below works, though scoring is not implemented. Please help me find out how this code could be made better, more idiomatic JavaScript, or more efficient.

// global variables
var canvas = document.getElementById("game");
var context = canvas.getContext("2d");
var colors = ["#FF7F34", "#FF4D79", "#FFEF42", "#78E853", "#64C4FF", "#954FFF"];
var squareSize = 20;
var canvasSize = 14;
var buttonSize = 30;
var spaceSize = 15;
var board = [];
var currentColor = 0;

// draw 14x14 board of randomly coloured squares and add each square to 2d array 'board'
function drawBoard(colors) {
    // draw main board
    for (var i = 0; i < canvasSize; i++) {
        var boardColumn = [];
        for (var j = 0; j < canvasSize; j++) {
            colorId = Math.floor((Math.random() * 6)) + 1;
            context.fillStyle = colors[colorId - 1];   
            context.fillRect(i*squareSize, j*squareSize, squareSize, squareSize);
             if (i == 0 && j == 0) {
                currentColor = colorId;
                colorId = 0;
            }
            boardColumn.push(colorId);
        }
        board.push(boardColumn);
    }    
    // draw controls
    colors.forEach(function (value, i) {
        context.fillStyle = value;
        context.fillRect(i * (buttonSize + spaceSize) + spaceSize, squareSize * canvasSize + spaceSize, buttonSize, buttonSize);
    });
    expandOcean(currentColor);
    redrawBoard();
}
// click handler
function clickToColor(event) {
  var color = 0;
  var x = event.x;
  var y = event.y;
  x -= canvas.offsetLeft;
  y -= canvas.offsetTop;
  var controlsOffsetTop = squareSize * canvasSize + spaceSize; 
  colors.forEach(function(value, i) {
    if (x > (spaceSize + i * (spaceSize + buttonSize)) && x <= ((i + 1) * (spaceSize + buttonSize)) && y > controlsOffsetTop && y <= (controlsOffsetTop + buttonSize)) color = i + 1;
  });
    if (color != 0 && color != currentColor) 
        {
            currentColor = color;
            expandOcean(currentColor);
            redrawBoard();
        }
}
// flooding with chosen color
function expandOcean(color) {
    var touched = false;
    board.forEach(function(column, i) {
        column.forEach(function(value, j) {
            if (j + 1 < canvasSize && ((column[j] == 0 && column[j+1] == color) || (column[j] == color && column[j+1] == 0))) {
                board[i][j+1] = 0;
                board[i][j] = 0;
                touched = true;
            }
        });
    });
    board.forEach(function(column, i) {
        column.forEach(function(value, j) {
            if (i + 1 < canvasSize && ((column[j] == 0 && board[i + 1][j] == color) || (column[j] == color && board[i+1][j] == 0))) {
                board[i + 1][j] = 0;
                board[i][j] = 0;
                touched = true;
            }
        });
    });
    if (touched == true) expandOcean(color);
}

function redrawBoard() {
    board.forEach(function(column, i) {
        column.forEach(function(value, j) {
            if (board[i][j] == 0) {
                context.fillStyle = colors[currentColor - 1];
            } else {
                context.fillStyle = colors[board[i][j] - 1];
            }
            context.fillRect(i*squareSize, j*squareSize, squareSize, squareSize);
        }); 
    }); 
}

drawBoard(colors);
canvas.addEventListener('click', clickToColor, false);
<!DOCTYPE html>
<html>
<body>
    <canvas id="game" width="280" height="400"></canvas>
    <script type="text/javascript" src="game.js"></script>
</body>
</html>

\$\endgroup\$
  • 2
    \$\begingroup\$ The board is just a grid. Have you considered not using a <canvas>? \$\endgroup\$ – 200_success Jun 9 '16 at 9:19
  • \$\begingroup\$ I haven't considered it, but you are right - simple table would do as well. I just wanted to write this game in JS, and the mechanism would stay the same, only output interface would be different. \$\endgroup\$ – greenbike Jun 9 '16 at 10:56
1
\$\begingroup\$

This would be so much easier with the use of a table or divs. You could then create an array of objects (one object per square). Ex:

[
    {
        "className": "orange",
        "x": 0,
        "y": 0
    }
];

By doing this, you can match the class of the surrounding objects, rather than changing the color directly. Hope this helps.

\$\endgroup\$
  • \$\begingroup\$ Make sure to match "className" to a css class. \$\endgroup\$ – Confettimaker Jun 27 '16 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.