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处下载。

动手学Javascript(1)——PopStar的更多相关文章

  1. 怎么学JavaScript?

    作者:小不了链接:https://zhuanlan.zhihu.com/p/23265155来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 鉴于时不时,有同学私信问我( ...

  2. 统一回复《怎么学JavaScript?》

    作者:小不了链接:https://zhuanlan.zhihu.com/p/23265155来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 鉴于时不时,有同学私信问我( ...

  3. 从头开始学JavaScript (十一)——Object类型

    原文:从头开始学JavaScript (十一)--Object类型 一.object类型 一个object就是一系列属性的集合,一个属性包含一个名字(属性名)和一个值(属性值). object对于在应 ...

  4. 从头开始学JavaScript (十二)——Array类型

    原文:从头开始学JavaScript (十二)--Array类型 一.数组的创建 注:ECMAscript数组的每一项都可以保存任何类型的数据 1.1Array构造函数 var colors = ne ...

  5. 从头开始学JavaScript (十)——垃圾收集

    原文:从头开始学JavaScript (十)--垃圾收集 一.垃圾收集 1.1javascript垃圾收集机制: 自动垃圾收集,执行环境会负责管理代码执行过程中的使用的内存.而在C和C++之类的语言中 ...

  6. 从头开始学JavaScript (九)——执行环境和作用域

    原文:从头开始学JavaScript (九)--执行环境和作用域 一.执行环境:定义了变量或者函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有与之关联的变量对象. 变量对象:保存着环境中 ...

  7. 从头开始学JavaScript (八)——变量

    原文:从头开始学JavaScript (八)--变量 一.变量分类: 基本类型值:null.undefined.number.string.Boolean: 引用类型值:保存在内存中的对象,如:Obj ...

  8. 从头开始学JavaScript (七)——函数

    原文:从头开始学JavaScript (七)--函数 一.return 函数在执行完return之后停止并立即退出. return返回值:与return: 如下两个例子: function sum(n ...

  9. 从头开始学JavaScript (六)——语句

    原文:从头开始学JavaScript (六)--语句 一.条件分支语句:if 基本格式: if (<表达式1>){    <语句组1>}else if (<表达式2> ...

随机推荐

  1. DDB与DIB的区别

    DDB(设备相关位图) DDB依赖于具体设备:DDB的颜色模式必需与输出设备相一致.例如,如果当前的显示设备是256色模式,那么DDB必然也是256色的.在256色以下的位图中存储的像素值是系统调色板 ...

  2. OJ python答题结果"返回非零"

    最近在OJ上用python答题,偶尔会遇到结果“放回非零”的情况(Non-zero Exit Code) 总结了以下,目前知道的是这些: 1. 在python2中用了input(),或在python3 ...

  3. BZOJ 1614: [Usaco2007 Jan]Telephone Lines架设电话线

    题目 1614: [Usaco2007 Jan]Telephone Lines架设电话线 Time Limit: 5 Sec  Memory Limit: 64 MB Description Farm ...

  4. Agg学习笔记

    很久前就听一大牛说起Agg,据说是一个架构极度牛B的2D引擎,沉寂了许久,最后花了两周时间走马观花地把它过了一遍.果然如那大牛所言,这家伙简直就是巧夺天工的艺术品.今天稍稍瞄了一下Google扔出来的 ...

  5. hdu4597 Play Game

    Play Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total Sub ...

  6. MFC下的日历表

    // CalenderDlg.h : header file // #if !defined(AFX_CALENDERDLG_H__8DC8F113_2A47_45B8_8266_75CB406D68 ...

  7. c 中有关打印*,字符的题目集

    #include<stdio.h> //1.打印* void priStar() { printf("输入一个整数\n"); int num; scanf(" ...

  8. 断开/删除 SVN 链接(.svn)的几种方法

    上传到正式的服务器时需要去掉这些不必要的文件,找到了几种方法: 1.windows下: xcopy project_dir project_dir_1 /s /i (从project_dir 复制文件 ...

  9. ThinkPHP分页类

    第一种:利用Page类和limit方法 $User = M('User'); // 实例化User对象$count      = $User->where('status=1')->cou ...

  10. 基于visual Studio2013解决算法导论之018栈实现(基于链表)

     题目 用链表实现栈 解决代码及点评 #include <stdio.h> #include <stdlib.h> #include <time.h> #in ...