动手学Javascript(1)——PopStar

PopStar是一款很流行的手机游戏。它的基本规则是在某个方块上单击,如果该方块周围有和它颜色一样的方块,那么这些方块都被选中。之后在选中方块的某一个上再次单击,所有选中的方块就会消失。

如下图所示,7个绿色的方块被选中(选中的方块被白色的框包围):

动手学Javascript(1)——PopStar

在选中的方块再次单击,这些绿色的方块就会消失。如果这些方块的上方就其他方块,上方的方块会掉下来。如果某一列全被消失,那么右边的列会自动左移。7块选中的绿色方块消失之后的效果如下图所示:

动手学Javascript(1)——PopStar

HTML代码如下所示:

 

<!DOCTYPE html>

<html>

    <head>

        <meta charset=utf-8 />

        <title>PopStar</title>

        <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />

        <script src="http://code.jquery.com/jquery-1.9.1.js"></script>

        <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>

        <script src="PopStar.js" type="text/javascript">

        </script>

        <link rel="stylesheet" type="text/css" href="PopStar.css" />

    </head>

    <body>

        <h1>Welcome to PopStar</h1>

        <div id="totalScore">Total Score: 0</div>

        <div id="currentScore">Click to Select.</div>

        <div id="mainCanvas">

        </div>

        <div id="notification">

            <div id="message"></div>

        </div>

    </body>

</html>

从上述代码可以看出,我们将会用到JQuery及jQuery UI的相关功能。

 

CSS的代码如下所示:

 

#mainCanvas {

    background-color: black;

    width: 300px;

    height: 300px;

}



.block {

    position: fixed;

    height: 28px;

    width: 28px;

    border-radius: 4px;

}



.selected {

    height: 26px;

    width: 26px;

    border-color: white;

    border-style: solid;

    border-width: 1px;

}

CSS主要定义了游戏的背景,以及方块(选中或未选中)的外观。

 

游戏的功能主要用Javascript实现,如下所示:

 

$(document).ready(function () {

    var sharedData;

    initGame();

    startGame();



    function initGame() {

        sharedData = {};

        sharedData.size = 10;



        var canvas = $('#mainCanvas');

        var width = parseInt(canvas.css('width'));

        var height = parseInt(canvas.css('height'));

        if (width != height) {

            alert('the canvas should be a square.');

        }

        sharedData.canvas = canvas;

        sharedData.blockLength = width / sharedData.size;

        sharedData.matrix = initMatrix();



        $('#notification').dialog({

            width: 400,

            resizable: false,

            modal: true,

            buttons: [{ text: "Ok", click: function () { $(this).dialog("close"); location.reload(); } }]

        });

    }



    function startGame() {

        sharedData.size = 10;

        sharedData.status = 0; // possible values: 0, 1

        sharedData.totalScore = 0;



        clearMatrix();



        initBlocks(sharedData);

        moveBlocks();



        clearCurrentScore();

        clearTotalScore();

        hideNotification();



        if (isGameOver()) {

            showNotification();

        }

    }



    function initBlocks(data) {

        var size = data.size;

        var row, col, value;

        var singleColor = size * size / 4;

        var divString;

        var newRow, newCol, index;



        $('.block').each(function () {

            $(this).remove();

        });



        var randomArray = getRandomArray(data.size);



        for (row = 0; row < size; ++row) {

            for (col = 0; col < size; ++col) {

                if (row * size + col < singleColor) {

                    value = 1;

                }

                else if (row * size + col < singleColor * 2) {

                    value = 2;

                }

                else if (row * size + col < singleColor * 3) {

                    value = 3;

                }

                else {

                    value = 4;

                }

                

                index = randomArray[row * size + col];

                newRow = Math.floor(index / size);

                newCol = index % size;



                divString = '<div class="block" currow="0" curcol="0" nextrow="' + newRow.toString()

                    + '" nextcol="' + newCol.toString() + '" value="' + value.toString() + '"></div>';

                $('#mainCanvas').append(divString);

            }

        }

    }



    function getRandomArray(size) {

        var total = size * size;

        var array = new Array(total);

        var i, index, temp;

        

        for (i = 0; i < array.length; ++i) {

            array[i] = i;

        }

        

        for (i = array.length - 1; i > 0; --i) {

            index = Math.floor(Math.random() * total);



            temp = array[i];

            array[i] = array[index];

            array[index] = temp;

        }

        

        return array;

    }



    function moveBlocks() {

        $('.block').each(function () {

            var nextRow = $(this).attr('nextrow');

            var nextCol = $(this).attr('nextcol');

            var value = $(this).attr('value');

            var parentPos = $(this).parent().offset();

            var top = parseInt(nextRow) * sharedData.blockLength + parentPos.top + 1;

            var left = parseInt(nextCol) * sharedData.blockLength + parentPos.left + 1;

            var cssTop = top.toString() + 'px';

            var cssLeft = left.toString() + 'px';

            var colors = ['#aaaaaa', '#3333cc', '#33cc33', '#cc3333', '#cccc33'];



            $(this).animate({

                top: cssTop,

                left: cssLeft

            },

            500);



            $(this).css({

                'background-color': colors[parseInt(value)]

            });



            $(this).attr('currow', nextRow);

            $(this).attr('curcol', nextCol);

        });

    }



    $('.block').click(function () {

        var clickedBlock = getClickedBlockPos($(this));

        var sameColorBlocks;



        clearMatrix();

        sameColorBlocks = getBlocksWithSameColor(clickedBlock.row, clickedBlock.col);

        updateStatus(clickedBlock.row, clickedBlock.col, sameColorBlocks);

    });



    function updateStatus(row, col, sameColorBlocks) {

        if (sameColorBlocks.length > 1) {

            if (sharedData.status == 0) {

                sharedData.status = 1;

                setSelectedBlocks(sameColorBlocks);

            }

            else {

                if (isClickAgain(row, col, sameColorBlocks)) {

                    moveMatrix(sharedData.matrix, sameColorBlocks);

                    sharedData.status = 0;

                    updateTotalScore(sharedData, sameColorBlocks.length);

                    clearSelectedBlocks();

                    moveBlocks();



                    clearMatrix();

                    if (isGameOver()) {

                        showNotification();

                    }

                }

                else {

                    setSelectedBlocks(sameColorBlocks);

                }

            }

        }

        else if (sharedData.status == 1) {

            sharedData.status = 0;

            clearSelectedBlocks();

        }

    }



    function moveMatrix(matrix, sameColorBlocks) {

        moveMatrixDown(matrix, sameColorBlocks);

        moveMatrixLeft(matrix);

        deleteBlocks();

        updateBlockPosition();

    }



    function updateBlockPosition() {

        $('.block').each(function () {

            var curRow = parseInt($(this).attr('currow'));

            var curCol = parseInt($(this).attr('curcol'));



            var moveDown = sharedData.matrix[curRow][curCol].moveDown;

            var moveLeft = sharedData.matrix[curRow][curCol].moveLeft;



            var nextRow = curRow + moveDown;

            var nextCol = curCol - moveLeft;



            $(this).attr('nextrow', nextRow.toString());

            $(this).attr('nextcol', nextCol.toString());

        });

    }



    function deleteBlocks() {

        $('.block').each(function () {

            var curRow = parseInt($(this).attr('currow'));

            var curCol = parseInt($(this).attr('curcol'));

    

            if (sharedData.matrix[curRow][curCol].value == 0) {

                $(this).remove();

            }

        });

    }



    function moveMatrixDown(matrix, toBeDeleted) {

        var i, j;



        toBeDeleted.sort(sortPosition);



        for (i = 0; i < toBeDeleted.length; ++i) {

            matrix[toBeDeleted[i].row][toBeDeleted[i].col].value = 0;



            for (j = toBeDeleted[i].row ; j >= 0; --j) {

                matrix[j][toBeDeleted[i].col].moveDown += 1;

            }

        }

    }



    function moveMatrixLeft(matrix) {

        for (i = 0; i < matrix.length; ++i) {

            if (isColumnBlank(matrix, i)) {

                moveColumnsLeft(matrix, i);

            }

        }

    }



    function moveColumnsLeft(matrix, col) {

        var i, j;

        for(i = 0; i < matrix.length; ++i) {

            for (j = col + 1; j < matrix.length; ++j)

                matrix[i][j].moveLeft += 1;

            }

    }



    function isColumnBlank(matrix, col) {

        var row;

        for (row = 0; row < matrix.length; ++row) {

            if (matrix[row][col].value != 0)

                return false;

        }



        return true;

    }



    function sortPosition(pos1, pos2) {

        if ((pos1.col < pos2.col) || (pos1.col == pos2.col && pos1.row > pos2.row))

            return -1;

        if (pos1.col == pos2.col && pos1.row == pos2.row)

            return 0;

        return 1;

    }



    function setSelectedBlocks(sameColorBlocks) {

        $('.block').each(function () {

            if ($(this).hasClass('selected')) {

                $(this).removeClass('selected');

            }

        });



        $('.block').each(function () {

            var curRow = parseInt($(this).attr('currow'));

            var curCol = parseInt($(this).attr('curcol'));



            if(isSelected(sameColorBlocks, curRow, curCol) && !$(this).hasClass('selected')) {

                $(this).addClass('selected');

            }

        });



        setCurrentScore(sameColorBlocks.length);

    }



    function isSelected(sameColorBlocks, row, col) {

        for (var i = 0; i < sameColorBlocks.length; ++i) {

            if (sameColorBlocks[i].row == row && sameColorBlocks[i].col == col) {

                return true;

            }

        }



        return false;

    }



    function clearSelectedBlocks() {

        $('.block').each(function () {

            if ($(this).hasClass('selected')) {

                $(this).removeClass('selected');

            }

        });



        clearCurrentScore();

    }



    function getClickedBlockPos(block) {

        var curRow = parseInt(block.attr('currow'));

        var curCol = parseInt(block.attr('curcol'));



        return {

            row: curRow,

            col: curCol

        };

    }



    function initMatrix() {

        var i, j;

        var size = sharedData.size;

        var rows = new Array(size);



        for (i = 0; i < size; ++i) {

            rows[i] = new Array(size);

            for (j = 0; j < size; ++j) {

                rows[i][j] = {

                    value: 0,

                    moveDown: 0,

                    moveLeft: 0

                };

            }

        }



        return rows;

    }



    function clearMatrix() {

        var i, j;

        var size = sharedData.size;

        var matrix = sharedData.matrix;



        for (i = 0; i < size; ++i) {

            for (j = 0; j < size; ++j) {

                matrix[i][j] = {

                    value: 0,

                    moveDown: 0,

                    moveLeft: 0

                };

            }

        }



        $('.block').each(function () {

            var value = parseInt($(this).attr('value'));

            var curRow = parseInt($(this).attr('currow'));

            var curCol = parseInt($(this).attr('curcol'));

            sharedData.matrix[curRow][curCol].value = value;

        });

    }



    function getBlocksWithSameColor(row, col) {

        var matrix = sharedData.matrix;

        var value = matrix[row][col].value, curValue;

        var matrixSize = matrix[0].length;

        var visited = new Array();

        var top, curRow, curCol, preRow, preCol;

        var sameColor = new Array();

        var i;



        var flag = new Array(matrixSize * matrixSize);

        for (i = 0; i < flag.length; ++i) {

            flag[i] = false;

        }



        addBlockWithSameColor(matrix, visited, sameColor, flag, row, col);



        while (visited.length > 0) {

            top = visited.pop();



            // left

            curRow = top.row;

            curCol = top.col - 1;

            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);



            // right

            curRow = top.row;

            curCol = top.col + 1;

            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);



            // up

            curRow = top.row - 1;

            curCol = top.col;

            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);



            // down

            curRow = top.row + 1;

            curCol = top.col;

            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);

        }



        return sameColor;

    }



    function addBlockWithSameColor(matrix, visited, sameColor, flag, row, col) {

        var cell = {

            row: row,

            col: col

        };



        visited.push(cell);

        sameColor.push(cell);

        flag[row * matrix[0].length + col] = true;

    }



    function addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol) {

        var matrixSize = matrix.length;

        var isOnBoundaryOrDiffColor = curRow >= 0 && curRow < matrixSize &&

            curCol >= 0 && curCol < matrixSize &&

            matrix[curRow][curCol].value == value;

        if (isOnBoundaryOrDiffColor && !flag[curRow * matrixSize + curCol]) {

            addBlockWithSameColor(matrix, visited, sameColor, flag, curRow, curCol);

        }

    }



    function isClickAgain(row, col, sameColor) {

        var result = false;



        $('.block').each(function () {

            var curRow = parseInt($(this).attr('currow'));

            var curCol = parseInt($(this).attr('curcol'));



            if(isSelected(sameColor, curRow, curCol) && $(this).hasClass('selected')) {

                result = true;

            }

        });



        return result;

    }



    function setCurrentScore(num) {

        var score = getScore(num);

        $('#currentScore').html('Selection Score: ' + score.toString());

    }



    function clearCurrentScore() {

        $('#currentScore').html('Click to Slect.');

    }



    function clearTotalScore() {

        $('#totalScore').html('Total Score: 0');

    }



    function getScore(num) {

        return 5 * num * num;

    }



    function updateTotalScore(data, num) {

        var score = getScore(num);

        data.totalScore += score;

        $('#totalScore').html('Total Score: ' + data.totalScore.toString());

    }



    function hideNotification() {

        $('#notification').dialog('close');

    }



    function showNotification() {

        $('#message').html('Game over. Click Ok to restart.');

        $('#notification').dialog('open');

    }



    function isGameOver() {

        var over = true;

        var curRow, curCol;

        var sameColor;



        $('.block').each(function () {

            if (over) {

                curRow = parseInt($(this).attr('currow'));

                curCol = parseInt($(this).attr('curcol'));



                sameColor = getBlocksWithSameColor(curRow, curCol);

                if (sameColor.length > 1) {

                    over = false;

                }

            }

        });



        return over;

    }

});

如果你对上述代码感兴趣,也可以到 http://download.csdn.net/detail/haitaohe/6702475处下载。

 

 

你可能感兴趣的:(JavaScript)