动手学Javascript(1)——PopStar
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的更多相关文章
- 怎么学JavaScript?
作者:小不了链接:https://zhuanlan.zhihu.com/p/23265155来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 鉴于时不时,有同学私信问我( ...
- 统一回复《怎么学JavaScript?》
作者:小不了链接:https://zhuanlan.zhihu.com/p/23265155来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 鉴于时不时,有同学私信问我( ...
- 从头开始学JavaScript (十一)——Object类型
原文:从头开始学JavaScript (十一)--Object类型 一.object类型 一个object就是一系列属性的集合,一个属性包含一个名字(属性名)和一个值(属性值). object对于在应 ...
- 从头开始学JavaScript (十二)——Array类型
原文:从头开始学JavaScript (十二)--Array类型 一.数组的创建 注:ECMAscript数组的每一项都可以保存任何类型的数据 1.1Array构造函数 var colors = ne ...
- 从头开始学JavaScript (十)——垃圾收集
原文:从头开始学JavaScript (十)--垃圾收集 一.垃圾收集 1.1javascript垃圾收集机制: 自动垃圾收集,执行环境会负责管理代码执行过程中的使用的内存.而在C和C++之类的语言中 ...
- 从头开始学JavaScript (九)——执行环境和作用域
原文:从头开始学JavaScript (九)--执行环境和作用域 一.执行环境:定义了变量或者函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有与之关联的变量对象. 变量对象:保存着环境中 ...
- 从头开始学JavaScript (八)——变量
原文:从头开始学JavaScript (八)--变量 一.变量分类: 基本类型值:null.undefined.number.string.Boolean: 引用类型值:保存在内存中的对象,如:Obj ...
- 从头开始学JavaScript (七)——函数
原文:从头开始学JavaScript (七)--函数 一.return 函数在执行完return之后停止并立即退出. return返回值:与return: 如下两个例子: function sum(n ...
- 从头开始学JavaScript (六)——语句
原文:从头开始学JavaScript (六)--语句 一.条件分支语句:if 基本格式: if (<表达式1>){ <语句组1>}else if (<表达式2> ...
随机推荐
- Java学习之链表
数据结构学了,java实现下 package com.gh.Link; /** * 链表的实现 * @author ganhang * */ public class Links { public s ...
- C++动态数组的实现
#include <iostream> using namespace std; int main() { int n; while(cin>>n) { ]; p[]=; p[ ...
- 破解企业QQ对个人QQ登陆的限制(原创)
运行系统:WIN7 破解时间:2014-02-19 破解思路:自从2013-11-11的1.85版企业qq更新后,网上流传的破解方法(运行文件BeatQQEIM.bat)已经不起作用了,可以同时登陆, ...
- 在vmware里面免费安装纯净的xp虚拟机
1. 安装vmware, 略 2. 下载xp http://msdn.itellyou.cn/ 用迅雷下载Windows XP Professional with Service Pack 3 (x8 ...
- Identifiers
Identifier An identifier is an arbitrarily long sequence of digits, underscores, lowercase and upper ...
- WebView之2
首先需要添加权限: <uses-permission android:name="android.permission.INTERNET"/> MainActivity ...
- 亚马逊带Marketplace product code的image无法再mount到其他镜像上
这是对已发布镜像的保护么?难道对其进行修改的路彻底断掉了? 以volume形式attach也不行,dd成raw再读取也读不了,敢问路在何方呢 If a volume has an AWS Market ...
- js中with、this的用法
with 语句 为一个或一组语句指定默认对象. 用法:with (<对象>) <语句>; with 语句通常用来缩短特定情形下必须写的代码量.在下面的例子中,请注意 Math ...
- IOS SWIFT 网络请求JSON解析 基础一
前言:移动互联网时代,网络通信已经是手机端必不可少的功能.应用中也必不可少地使用了网络通信,增强客户端与服务器交互.使用NSURLConnection实现HTTP的通信.NSURLConnection ...
- Nginx的500,502,504错误解决方法
Nginx的500,502,504错误解决方法 一.解决500错误: 1.500错误指的是服务器内部错误,也就是服务器遇到意外情况,而无法履行请求. 2.500错误一般有几种情况: (1)web脚本错 ...