这是我自己在学习jquery时突发奇想做的一个扫雷小游戏,主要用到的知识是html5,css3,javascript和jquery,用到的jquery版本是jquery-1.6.4.min,代码文件和库文件大家可以点这个链接进行下载 :用jquery做的扫雷小游戏代码和资源。以下就是我在做这个小游戏时的主要思路和代码。
准备工作
首先我们需要明确游戏的规则并以此来决定功能,并且要知道自己希望游戏的界面是什么样的。我的这个扫雷小游戏是通过我的一个课堂实验改编的,原本它只是一堆可以变颜色的格子而以。
下面是我的思路
- 首先要在网页上放置81个格子,所有格子统一样式,但每个格子的id都由行号和列号组成,便于查找(我这里格子是用p标签制作的)。
- 在81个格子中放置10个地雷,地雷的坐标自然是记录在数组中,而不是体现在格子中。
- 每个格子中放一个span标签元素,用于记录数字,默认为0,数字的作用代表周围地雷数,玩过扫雷的应该都知道。
- 给每一个span标签添加数字,方法是根据地雷的位置来判断,使得每个地雷周围的span标签元素的值加1。
- 添加格子的鼠标单击事件,当格子被点击时,进行判定,若该格子为地雷,则游戏结束,若不是地雷,则翻开格子(这里情况比较复杂,下面会详解,因为这涉及到地雷的自动翻开格子,就是你点的格子没有任何数字时,游戏会帮你自动翻开周围的格子一直到被数字包围)。
具体功能实现
先来定义好一些需要的样式(style),这里我们主要的是格子(p标签)的样式,格子被点开后的样式以及地雷被点开后的样式。这里我把正常被点开的格子的样式放在highlight类中,设置背景色为金色,而地雷被点开的颜色为红色,放在lowlight类中。p标签只有设置一点外边距和边框宽度就好了,然后设置浮动为左浮动。因为我们需要把81个格子变成9*9排列,每一排格子都要放在一个div中,所以还有设置一个div样式。
<style type="text/css">
body { width:760px; }
div { margin:5px 10px; clear:both; }
p { float:left; margin:3px; width:30px; height:30px; border:2px solid black; text-align:center; display:table;}
.highlight { background-color:gold; }
.lowlight{background-color:red;}
</style>
然后引入一下jquery的库文件。记住要把jquery文件和网页文件放在同一个文件夹内。
<script src="jquery-1.6.4.min.js" type="text/javascript"></script>
定义好样式后,就可以在页面上放置格子了,这里我用了两个for循环,第一个用来产生div(代表一行),第二个用来在div中产生p(格子)。
//产生一个9*9的格子地图
for(var i=0;i<9;i++){
$("body").append("<div id='"+i+"i'></div>");
for(var j=0;j<9;j++){
$("#"+i+"i").append("<p id='"+i+"i"+j+"j'><span style='display:table-cell;vertical-align:middle;visibility:hidden;'>0</span></p>");
}
}
哈哈,是不是感觉span标签的定义很长,这里先解释一下为什么要给span标签这么多style的属性,其中display:table-cell表示span会作为表格单元格显示,而span的父元素p标签的样式中,定义了display:table(见第一段代码),这两个display的属性和vertical-align能够使得span标签垂直居中显示,说白了这个属性是为了好看用的。visibility:hidden,这个属性是为了隐藏span标签,为什么要隐藏?因为在我们点格子之前可不希望看到格子里的数字,数字代表着周围地雷数。
这样我们就把格子定义好了,然后就是产生10 个地雷了,这里我定义了两个一维数组,分别用于存储地雷的行号和列号(从0~8)。其中Math.floor()函数用于产生整数,Math.random()用于产生随机数。这两个函数同时使用用于产生随机整数。
var aa=[0]; //地雷横坐标
var bb=[0]; //地雷纵坐标
var flag=true; //判断是否产生了重复坐标
//产生不重复的10个整数并存入aa,bb数组中,作为地雷坐标
for(var i=0;i<10;i++){
aa[i]=Math.floor(Math.random()*9);
bb[i]=Math.floor(Math.random()*9);
for(var j=0;j<i;j++){
if(aa[i]==aa[j]&&bb[i]==bb[j]){
i--;
flag=false;
break;
}
}
if(flag==false){
flag=true;
}else{
console.log(aa[i],bb[i]);
}
}
这里console.log()函数的作用仅用于调试,在测试时可以打开网页,按F12在Console中查看产生的地雷坐标
地雷产生后,就需要根据地雷坐标,给周围的span元素赋值了,由于一开始所有span元素的值都为0,所以我们要做的就是给地雷周围的每一个span元素的值+1。当然,我们需要先获取span元素的值,然后+1,再赋值给它。这里代码不复杂,只是看着长而已。
//给每个地雷周围的格子加数字,数字代表周围地雷数
var z=[""]; //记录地雷周围p的id;
for(var i=0;i<10;i++){
x=aa[i];
x1=x-1;
x2=x+1;
y=bb[i];
y1=y-1;
y2=y+1;
//获取每个p的id;
z[0]="#"+x1+"i"+y1+"j";
z[1]="#"+x1+"i"+y+"j";
z[2]="#"+x1+"i"+y2+"j"
z[3]="#"+x+"i"+y1+"j";
z[4]="#"+x+"i"+y2+"j";
z[5]="#"+x2+"i"+y1+"j";
z[6]="#"+x2+"i"+y+"j";
z[7]="#"+x2+"i"+y2+"j";
$(z[0]).children().html(Number($(z[0]).children().html())+1);
$(z[1]).children().html(Number($(z[1]).children().html())+1);
$(z[2]).children().html(Number($(z[2]).children().html())+1);
$(z[3]).children().html(Number($(z[3]).children().html())+1);
$(z[4]).children().html(Number($(z[4]).children().html())+1);
$(z[5]).children().html(Number($(z[5]).children().html())+1);
$(z[6]).children().html(Number($(z[6]).children().html())+1);
$(z[7]).children().html(Number($(z[7]).children().html())+1);
}
最后一步是重中之重,就是给p标签添加点击事件了。下面我先展示一下p标签点击事件的流程图。
这里下半部分的逻辑有点复杂,我可能没有清晰的表达出来,总而言之就是一个递归调用的过程,当检测函数checkBlank()发现被点击格子周围的某个格子的值为0时,会对这个格子调用checkBlank()函数,重新进行检测。打个比方,你点了一个值为0的格子(这是主角),checkBlank()会先检查该格子左上角的格子,如果左上角的格子的值也为0,且没被翻开,也不是地雷,那么左上角的格子就成了一个新的主角,checkBlank()函数会先对新的主角进行检测了。以此来模拟扫雷时,点击了一个周围没雷的格子,然后系统会自动帮你翻开所有的空白格子。下面是该功能的代码。
var zz=[""]; //记录地雷所在p的id
for(var i=0;i<10;i++){
zz[i]=aa[i]+"i"+bb[i]+"j";
}
//p标签点击事件
jQuery("p").click(function(){
var k=$(this).parent().index(); //p所在行
var n=$(this).attr("id"); //p的id
var t=$(this).parent().children("#"+n+"").index(); //p所在列
var gameOver=false; //游戏结束的标志
for(var i=0;i<10;i++){
if(k==aa[i]&&t==bb[i]){
gameOver=true;
}
}
if(gameOver==true){
for(var i=0;i<10;i++){
$("#"+aa[i]+"i"+bb[i]+"j").addClass("lowlight");
}
setTimeout(alertGame,100);
function alertGame(){
alert("你输了");
setTimeout(window.location.reload()); //刷新页面
}
}else{
$(this).children().css("visibility","visible"); //显示格子周围地雷数
$(this).addClass("highlight"); //设置格子背景色为高亮
if(Number($(this).children(0).html())==0){
var currentBlank=$(this);
checkBlank(currentBlank);
}
}
//检测空白格子是否需要被翻开
function checkBlank(aBlank){
var a=aBlank.index();
var b=a-1;
var c=a+1;
var d=aBlank.parent().prev().children(":eq("+b+")").children();
judge(d);
d=aBlank.parent().prev().children(":eq("+a+")").children();
judge(d);
d=aBlank.parent().prev().children(":eq("+c+")").children();
judge(d);
d=aBlank.parent().next().children(":eq("+b+")").children();
judge(d);
d=aBlank.parent().next().children(":eq("+a+")").children();
judge(d);
d=aBlank.parent().next().children(":eq("+c+")").children();
judge(d);
d=aBlank.prev().children();
judge(d);
d=aBlank.next().children();
judge(d);
//主要的判断函数,若满足两个条件则可以被翻开,1.格子内span元素的visibility属性为hidden. 2.格子不是地雷
function judge(e){
if(Number(e.html())!=0&&e.css("visibility")=="hidden"&&checkBoom(e.parent())==false){
e.css("visibility","visible");
e.parent().addClass("highlight");
}else if(Number(e.html())==0&&e.css("visibility")=="hidden"&&checkBoom(e.parent())==false){
e.css("visibility","visible");
e.parent().addClass("highlight");
checkBlank(e.parent());
}
}
function checkBoom(f){
var g=f.attr("id");
var gg=false;
for(var i=0;i<10;i++){
if(g==zz[i]){
gg=true;
break;
}
}
return gg;
}
}
});
写到这里,我们的扫雷游戏就完成了,不过这个小游戏还是有很多地方可以完善的,我没有继续做下去,大家可以自己去尝试的做一下。比如游戏胜利条件的判断,标注地雷的功能。大家如果需要资源的可以点下面这个链接进行下载。
用jquery做的扫雷小游戏代码和资源
以下是完整代码
<!DOCTYPE html >
<html>
<head>
<meta charset="utf-8"/>
<title>扫雷</title>
<style type="text/css">
body { width:760px; }
div { margin:5px 10px; clear:both; }
p { float:left; margin:3px; width:30px; height:30px; border:2px solid black; text-align:center; display:table;}
.highlight { background-color:gold; }
.lowlight{background-color:red;}
</style>
<script src="../jquery-1.6.4.min.js" type="text/javascript"></script>
<script>
jQuery(document).ready(function(){
//产生一个9*9的格子地图
for(var i=0;i<9;i++){
$("body").append("<div id='"+i+"i'></div>");
for(var j=0;j<9;j++){
$("#"+i+"i").append("<p id='"+i+"i"+j+"j'><span style='display:table-cell;vertical-align:middle;visibility:hidden;'>0</span></p>");
}
}
var aa=[0]; //地雷横坐标
var bb=[0]; //地雷纵坐标
var flag=true; //判断是否产生了重复坐标
//产生不重复的10个整数并存入aa,bb数组中,作为地雷坐标
for(var i=0;i<10;i++){
aa[i]=Math.floor(Math.random()*9);
bb[i]=Math.floor(Math.random()*9);
for(var j=0;j<i;j++){
if(aa[i]==aa[j]&&bb[i]==bb[j]){
i--;
flag=false;
break;
}
}
if(flag==false){
flag=true;
}else{
console.log(aa[i],bb[i]);
}
}
//给每个地雷周围的格子加数字,数字代表周围地雷数
var z=[""]; //记录地雷周围p的id;
for(var i=0;i<10;i++){
x=aa[i];
x1=x-1;
x2=x+1;
y=bb[i];
y1=y-1;
y2=y+1;
//获取每个p的id;
z[0]="#"+x1+"i"+y1+"j";
z[1]="#"+x1+"i"+y+"j";
z[2]="#"+x1+"i"+y2+"j"
z[3]="#"+x+"i"+y1+"j";
z[4]="#"+x+"i"+y2+"j";
z[5]="#"+x2+"i"+y1+"j";
z[6]="#"+x2+"i"+y+"j";
z[7]="#"+x2+"i"+y2+"j";
$(z[0]).children().html(Number($(z[0]).children().html())+1);
$(z[1]).children().html(Number($(z[1]).children().html())+1);
$(z[2]).children().html(Number($(z[2]).children().html())+1);
$(z[3]).children().html(Number($(z[3]).children().html())+1);
$(z[4]).children().html(Number($(z[4]).children().html())+1);
$(z[5]).children().html(Number($(z[5]).children().html())+1);
$(z[6]).children().html(Number($(z[6]).children().html())+1);
$(z[7]).children().html(Number($(z[7]).children().html())+1);
}
var zz=[""]; //记录地雷所在p的id
for(var i=0;i<10;i++){
zz[i]=aa[i]+"i"+bb[i]+"j";
}
//p标签点击事件
jQuery("p").click(function(){
var k=$(this).parent().index(); //p所在行
var n=$(this).attr("id"); //p的id
var t=$(this).parent().children("#"+n+"").index(); //p所在列
var gameOver=false; //游戏结束的标志
for(var i=0;i<10;i++){
if(k==aa[i]&&t==bb[i]){
gameOver=true;
}
}
if(gameOver==true){
for(var i=0;i<10;i++){
$("#"+aa[i]+"i"+bb[i]+"j").addClass("lowlight");
}
setTimeout(alertGame,100);
function alertGame(){
alert("你输了");
setTimeout(window.location.reload()); //刷新页面
}
}else{
$(this).children().css("visibility","visible"); //显示格子周围地雷数
$(this).addClass("highlight"); //设置格子背景色为高亮
if(Number($(this).children(0).html())==0){
var currentBlank=$(this);
checkBlank(currentBlank);
}
}
//检测空白格子是否需要被翻开
function checkBlank(aBlank){
var a=aBlank.index();
var b=a-1;
var c=a+1;
var d=aBlank.parent().prev().children(":eq("+b+")").children();
judge(d);
d=aBlank.parent().prev().children(":eq("+a+")").children();
judge(d);
d=aBlank.parent().prev().children(":eq("+c+")").children();
judge(d);
d=aBlank.parent().next().children(":eq("+b+")").children();
judge(d);
d=aBlank.parent().next().children(":eq("+a+")").children();
judge(d);
d=aBlank.parent().next().children(":eq("+c+")").children();
judge(d);
d=aBlank.prev().children();
judge(d);
d=aBlank.next().children();
judge(d);
//主要的判断函数,若满足两个条件则可以被翻开,1.格子内span元素的visibility属性为hidden. 2.格子不是地雷
function judge(e){
if(Number(e.html())!=0&&e.css("visibility")=="hidden"&&checkBoom(e.parent())==false){
e.css("visibility","visible");
e.parent().addClass("highlight");
}else if(Number(e.html())==0&&e.css("visibility")=="hidden"&&checkBoom(e.parent())==false){
e.css("visibility","visible");
e.parent().addClass("highlight");
checkBlank(e.parent());
}
}
function checkBoom(f){
var g=f.attr("id");
var gg=false;
for(var i=0;i<10;i++){
if(g==zz[i]){
gg=true;
break;
}
}
return gg;
}
}
});
});
</script>
</head>
<body>
</body>
</html>