PopStar是一款很流行的手机游戏。它的基本规则是在某个方块上单击,如果该方块周围有和它颜色一样的方块,那么这些方块都被选中。之后在选中方块的某一个上再次单击,所有选中的方块就会消失。
如下图所示,7个绿色的方块被选中(选中的方块被白色的框包围):
在选中的方块再次单击,这些绿色的方块就会消失。如果这些方块的上方就其他方块,上方的方块会掉下来。如果某一列全被消失,那么右边的列会自动左移。7块选中的绿色方块消失之后的效果如下图所示:
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处下载。