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. AFNetworking GET和POST请求

    GET请求 代码展示: 在storyBoard中每个请求关联一个Button #pragma mark - get请求 - (IBAction)getRequest:(id)sender { // 参 ...

  2. Dijkstra 模板 最短路

    转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents ------------------------------------------ ...

  3. linux 内核头文件 linux kernel header

    概述:在进行有关系统软件的安装的时候(编译一个新的驱动,或者安装一个系统级别的测试工具,例如systemtap),经常需要重新编译内核,相应的问题往往与内核头文件有关.那么,什么是内核头文件,为什么需 ...

  4. iOS 开发http post 文件的上传

    iOS开发网络篇—文件的上传 说明:文件上传使用的时POST请求,通常把要上传的数据保存在请求体中.本文介绍如何不借助第三方框架实现iOS开发中得文件上传. 由于过程较为复杂,因此本文只贴出部分关键代 ...

  5. [NOIP 2005]-- 篝火晚会

    额~~,对这组题感兴趣的具体的解题报告可以戳戳这里:http://wenku.baidu.com/view/878beb64783e0912a2162aa7.html?qq-pf-to=pcqq.c2 ...

  6. BZOJ 1458: 士兵占领( 网络流 )

    先判无解 把整个棋盘都放上士兵, 只需求最多可以拿走多少个士兵即可.每一行看做一个点r(i), 每一列看做一个点c(i) S->r(i), c(i)->T 连边, 容量为可以拿走的最大士兵 ...

  7. Android中的TextView实现多行显示省略号

    今天遇到一个问题就是TextView显示内容的时候,多行显示的时候,显示省略号的问题,刚开始没有找到一个好的办法,只找到一个自定义TextView组件的方法,然而今天在贴吧中找到一个更好,更简便的方法 ...

  8. hibernate报错

    报错二:java.lang.ExceptionInInitializerError java.lang.ExceptionInInitializerError at com.java1234.serv ...

  9. 微信红包API接口(PHP)

    根据微信高级红包接口,开发PHP版本的API接口,现在进行主要代码分析. 红包接口调用请求代码,所有请求参数为必填参数与文档对应: class Wxapi { private $app_id = 'w ...

  10. Corrupted MAC on input at /usr/local/perl/lib/site_perl/5.22.1/x86_64-linux/Net/SSH/Perl/Packet.pm l

    <pre name="code" class="python">[Thu May 5 11:02:27 2016] [error] Corrupte ...