前言
还是js小游戏系列,这次带来扫雷小游戏的开发思路
功能说明
仿照以前windows上自带的扫雷小游戏
设置棋盘大小,地雷密度等
包含计时器(单位:秒)
- 鼠标左键 - - 掀开一块区域
- 左键双击 - - 掀开周边8个区域
- 鼠标右键 - - 标记一个区域
- 数字代表周边8个区域包含的地雷数
- 胜利条件:将所有地雷全都标记出来
- 失败条件:掀开了地雷区域
操作截图
关键方法及设计思路
1.定义了两个区域:信息区,扫雷区
2.初始化方法:
设置棋盘大小,地雷密度,
随机设置地雷,
计算地雷预警数字
3.鼠标左键单击操作
如果掀开是空白区域,需要向周边扩散掀开其他区域,直到掀开数字为止
4.鼠标左键双击操作
需要计算周边8个区域的坐标,调用单击方法
5.鼠标右键单击操作
设置地雷标记,需要注意屏蔽浏览器默认的右键菜单
6.设置地雷的随机算法
将棋盘从二维转换成了单数组,获取相对应的随机数,再转换成二维坐标.
其它
相对来说,设计的复杂程度要比俄罗斯方块少很多.
后续可以对随机算法进行改进,比如在第一次单击操作时才对雷区进行初始化,避免第一步就爆雷的情况出现
详细代码
<html>
<style>
select{
width: 120px;
}
td {
width: 28px;
height: 28px;
margin: 1px;
background: #0C0C0C;
align-content: center;
}
#info td{
color: white;
}
#table td{
/*color: #2135ff;*/
text-align:center
}
</style>
<body id="body">
<table id="info">
<tr>
<td>
<label>LEVEL:</label>
</td>
<td>
<select id="level">
<option value="10">easy</option>
<option value="7">normal</option>
<option value="5">hard</option>
<option value="3">crazy</option>
</select>
</td>
</tr>
<tr>
<td>
<label>Field:</label>
</td>
<td>
<select id="field">
<option value="10_10">min(10*10)</option>
<option value="15_15">normal(15*15)</option>
<option value="20_20">max(20*20)</option>
</select>
</td>
</tr>
<tr>
<td>
<label>BoomCount:</label>
</td>
<td>
<p id="boomCount">0</p>
</td>
</tr>
<tr>
<td>
<label>Time:</label>
</td>
<td>
<p id="time">0</p>
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">
<button onclick="refresh()" style="width: 120px;">Play</button>
</td>
</tr>
</table>
</body>
<html>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
/**
* 指定背景和初始化操作
* @param w 宽(格字数)
* @param h 高(格字数)
* @constructor
*/
function Field(w, h, boomRate) {
//清除所有
$("#table").remove();
//默认宽10格
this.width = w ? w : 10;
//默认高10格
this.height = h ? h : 10;
//密度系数
this.boomRate = boomRate ? boomRate : 10;
//地雷总数
this.boomCount = parseInt(this.width * this.height / this.boomRate);
$("#boomCount")[0].innerText=this.boomCount;
//标记数
this.signCount = 0;
//显示
this.show = function () {
//创建信息区
$("#body").append("<div id='info'></div>");
//创建雷区table
$("#body").append("<table id='table'></table>");
var table = $("#table");
for (var i = 1; i <= this.height; i++) {
$(table).append("<tr id='tr_" + i + "'></tr>");
var tr = $("#tr_" + i);
for (var j = 1; j <= this.width; j++) {
$(tr).append("<td id='tr_" + i + "td_" + j + "' x='" + j + "' y='" + i + "'></td>");
$("#tr_" + i + "td_" + j);
}
$(table).append(tr);
}
//初始化地雷
this.boom();
//初始化td上的单击事件
$("#table td").click(function () {
if(over) return;
f.check(this);
});
//初始化td上的双击事件
$("#table td").dblclick(function () {
if(over) return;
f.dbClick(this);
});
//初始化td上的右击事件
$("#table td").mousedown(function (e) {
//已结束的直接返回
if(over) return;
//已掀开的直接返回
var status = $(this).attr("status");
if (status == "open") {
return;
}
//右键为3
if (3 == e.which) {
//判断当前状态
var boomSign = $(this).attr("boomSign");
if (boomSign != null) {
//取消标记
$(this).css("background", "#0C0C0C");
$(this).removeAttr("boomSign");
f.signCount--;
} else {
if (f.signCount < f.boomCount) {
f.signCount++
//打上标记
$(this).css("background", "#0070c0");
$(this).attr("boomSign", "boomSign");
//胜利判定
if (f.signCount == f.boomCount) {
if ($('td[boomSign="boomSign"],[boom="boom"]').length == f.boomCount) {
alert("YOU WIN!")
}
}
} else {
//没有多余的标记了
alert("too many sign!");
}
}
}
});
};
//初始化地雷
this.boom = function () {
//初始化地雷
var randoms = [];
while (true) {
var isExists = false;
// 获取一个1–100范围的数
var random = parseInt(1 + (this.width * this.height) * (Math.random()));
// 判断当前随机数是否已经存在
for (var i = 0; i < randoms.length; i++) {
if (random === randoms[i]) {
isExists = true;
break;
}
}
// 如果不存在,则添加进去
if (!isExists)
randoms.push(random);
// 如果有10位随机数了,就跳出
if (randoms.length === this.boomCount)
break;
}
//计算地雷坐标
var boomXY = [];
for (var i = 0; i < randoms.length; i++) {
var value = randoms[i];
var x = parseInt(value / this.width) + 1;
var y = value % this.width + 1;
boomXY[i] = {"x": x, "y": y};
$("#tr_" + y + "td_" + x).attr("boom", "boom");
}
//计算地雷周围数字
$("#table td").each(function () {
var td = this;
//地雷标志
var boom = $(td).attr("boom") == null ? false : true;
//不是地雷时,计算周围地雷数量
var scanCount = 0;
if (!boom) {
//寻找四周坐标
var around = f.around(td);
//遍历查询地雷
for (var i = 0; i < around.length; i++) {
var scanTd = $("#tr_" + around[i].y + "td_" + around[i].x);
var boomFlag = $(scanTd).attr("boom") == null ? false : true;
if (boomFlag) {
scanCount++;
}
}
}
if (scanCount > 0) {
$(td).attr("scanCount", scanCount);
}
})
};
//判断单击后的事件
this.check = function (td) {
//判断是否已经掀开
var status = $(td).attr("status");
if (status == "open") {
return;
}
//已标记的不能掀开
var boomSign = $(td).attr("boomSign");
if (boomSign != null) {
return;
}
//判断是否是雷
var boom = $(td).attr("boom") == null ? false : true;
if (boom) {
//踩中地雷,则失败,掀开所有地雷
$("td[boom='boom']").css("background", "#ff0000");
//锁定页面和时间
clearInterval(timer);
over=true;
alert("Boom~~~");
} else {
//赋值表示已经掀开
$(td).attr("status", "open");
//获取周边雷数
var scanCount = $(td).attr("scanCount");
//雷数全空,则向四周自动展开
if (scanCount == null || scanCount == "") {
//空白则直接掀开
$(td).css("background", "#dffed7");
//向周围八个方向蔓延
//寻找四周坐标
var around = f.around(td);
//遍历查询地雷
for (var i = 0; i < around.length; i++) {
var scanTd = $("#tr_" + around[i].y + "td_" + around[i].x);
$(scanTd).click();
}
} else {
//雷数不为空,显示底部的数字
$(td).css("background", "#dffed7")[0].innerText = scanCount;
}
}
};
//如果当前对象是数字,触发周边范围的单击事件
this.dbClick = function (td) {
//判断是不是数字
var scanCount = $(td).attr("scanCount");
if(scanCount!=null&&scanCount!=""){
//寻找四周坐标
var around = f.around(td);
//遍历查询地雷
for (var i = 0; i < around.length; i++) {
var scanTd = $("#tr_" + around[i].y + "td_" + around[i].x);
$(scanTd).click();
}
}
};
//获得周圈坐标
this.around = function (td) {
//自我坐标
var x = parseInt($(td).attr("x"));
var y = parseInt($(td).attr("y"));
//返回结果集
var around = [];
if (y > 1) {
//左上
if (x > 1) {
around.push({"x": x - 1, "y": y - 1});
}
//上
around.push({"x": x, "y": y - 1});
//右上
if (x < this.width) {
around.push({"x": x + 1, "y": y - 1});
}
}
//左
if (x > 1) {
around.push({"x": x - 1, "y": y});
}
//右
if (x < this.width) {
around.push({"x": x + 1, "y": y});
}
if (y < this.height) {
//左下
if (x > 1) {
around.push({"x": x - 1, "y": y + 1});
}
//下
around.push({"x": x, "y": y + 1});
//右下
if (x < this.width) {
around.push({"x": x + 1, "y": y + 1});
}
}
return around;
};
}
/**
* 初始化雷区
*/
function refresh() {
over=false;
//获取雷区大小
var area = $("#field").val().split("_");
var w = parseInt(area[0]);
var h = parseInt(area[1]);
//获取雷区密度
var level = parseInt($("#level").val());
//重置雷区
f = new Field(w, h, level);
f.show();
//重置计时器
$("#time")[0].innerText = 0;
clearInterval(timer);
timer = window.setInterval("var time = parseInt($('#time')[0].innerText);time++;$('#time')[0].innerText=time;", 1000);
}
//定义雷区
var f;
//定义计时器
var timer;
//结束标志
var over=false;
//屏蔽页面系统右键
document.oncontextmenu = function () {
return false;
}
</script>