做一个扫雷游戏
论游戏中,最深入人心的游戏是什么?最经典的游戏是什么?理所当然,是《扫雷》。
项目地址:项目地址
这就是游戏的整体ui。
首先制作游戏的h5骨架:
可以使用一个div作为容器来放置每个方格,至于时间表,可以最为图片:
index.html
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<title>扫雷</title>
<link rel="stylesheet" type="text/css" href="css/index.css"/>
<script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
<div id="info">
<span id="boomNum"><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="img/d0.bmp" id="b-h"/><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="img/d0.bmp" id="b-t"/><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="img/d0.bmp" id="b-o"/></span>
<img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="img/face_normal.bmp" class="face" id="start"/>
</div>
<div id="chess">
</div>
<script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="js/index.js"></script>
</body>
</html>
然后编写下css文件,设置html部件的样式
css/index.css
#chess{
border: #000 solid 1px;
margin: 10px auto;
}
.block{
width: 28px;
height: 28px;
margin: 0;
border: #000 solid 1px;
background-color: #eee;
float: left;
font-weight: bold;
text-align: center;
line-height: 30px;
font-size: 20px;
cursor: pointer;
}
.block:hover{
background-color: #ccc;
}
#info{
margin: 0 auto;
text-align: center;
}
.face{
border: 2px solid #808080;
border-left-color: #fff;
border-top-color: #fff;
height: 20px;
width: 20px
}
.face:active{
border-top:2px solid #808080;
border-bottom:1px solid #808080;
border-right:1px solid #808080;
border-left:2px solid #808080;
}
接下来就开始实现游戏的逻辑实现,首先初始化一些基本变量与数组:
var chess = [];// 存储雷区的值
const num = 100;// 存储地雷数
var surplusNum = num;// 存储剩余地雷数
var styles = [
"#00f",
"#0f0",
"#f00",
"#08f",
"#f30",
"#0fa",
"#943",
"#eee"
];// 存储不同数字的颜色样式
var die = false;// 存储是否游戏结束
var chessJq = $("#chess");// 为雷区的jQuery对象
var chessLength = 25;// 为雷区的边长
为了能在游戏结束后能重复开始游戏,则我们将一些初始化代码放入init函数中,并在开始调用它:
init();
function init() {
// 判断是否地雷数大于格子数
if (num > Math.pow(chessLength,2))
return;
// 设置雷区长宽
$("#chess").css({
"width": chessLength * 30,
"height": chessLength * 30
});
// 初始化雷区
for (let i = 0 ; i < chessLength ; i++){
chess[i] = [];
for (let j = 0 ; j < chessLength ; j++){
chess[i][j] = 0;
}
}
for (let i = 0 ; i < num ; i++){
while (true){
var x = Math.floor(Math.random() * chess.length),y = Math.floor(Math.random() * chess.length);
if (chess[y][x] == 0){
chess[y][x] = -1;
break;
}
}
}
// 初始化数字标记
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
if (chess[i][j] == -1)
continue;
chess[i][j] += get(i - 1,j);
chess[i][j] += get(i + 1,j);
chess[i][j] += get(i,j - 1);
chess[i][j] += get(i,j + 1);
chess[i][j] += get(i - 1,j - 1);
chess[i][j] += get(i + 1,j + 1);
chess[i][j] += get(i + 1,j - 1);
chess[i][j] += get(i - 1,j + 1);
}
}
// 清空雷区
chessJq.empty();
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
// chessJq.append("<div class='block' id='" + i + "-" + j + "' style='color: " + styles[chess[i][j] - 1] + "'></div>");
// if (chess[i][j] > 0){
// $("#" + i + "-" + j).html(chess[i][j]);
// }
chessJq.append("<div class='block' id='" + i + "-" + j + "'></div>");
}
}
surplusNum = num;
update();
}
function get(i,j) {
if (i < 0 || i >= chess.length || j < 0 || j >= chess.length)
return 0;
if (chess[i][j] == -1)
return 1;
return 0;
}
然后,接着实现点击雷区方格露出数字、与右击标记的代码,对此,可以添加一个mousedown的事件。
$(".block").mousedown(function (e) {
if (die)
return;
var me = $(this);
if (e.which == 1){// left click
open(me,true,0);
} else {// right click
if (me.html().search(/0/g) !== -1){
me.html("<img src='img/flag.bmp'/>");
surplusNum--;
update();
} else if (me.html().search(/flag/g) !== -1) {
me.html("<img src='img/ask.bmp'/>");
surplusNum++;
update();
} else {
me.html("<img src='img/0.bmp'>");
}
if (surplusNum == 0){
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
if (chess[i][j] == -1 && $("#" + i + "-" + j).html().search("flag") == -1){
die = true;
break;
}
}
}
if (die){
$("#start").attr("src","img/face_fail.bmp");
dieShow();
} else {
$("#start").attr("src","img/face-win.bmp");
}
}
}
});
细心的同学们肯定发现了,接着,我们要开始实现open函数,该函数应该有两个模式,一个是程序自动翻出附近的数字,一个是打开用户操作的方格。可以使用传一个布尔值来判断,并使用递归实现自动翻出附近的数字。
function open(me,canBoom,level) {
var id = me.attr("id");
var tmp = id.split("-");
var x = tmp[1] * 1;
var y = tmp[0] * 1;
if (level > 5){
return;
}
if (me.html().search(/flag/g) != -1 || me.html().search(/ask/g) != -1)
return;
if (chess[y][x] == -1 && canBoom){
me.html("<img src='img/blood.bmp'/>");
die = true;
$("#start").attr("src","img/face_fail.bmp");
dieShow();
} else if (chess[y][x] > 0){
me.html(chess[y][x]);
me.css({
"color": styles[chess[y][x]],
"background-image": "url(\"img/0.bmp\")"
});
let tmp = $("#" + y + "-" + x);
if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1)
return;
if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 ||
chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1
){
return;
}
open($("#" + (y - 1) + "-" + (x)),false,level + 1);
open($("#" + (y + 1) + "-" + (x)),false,level + 1);
open($("#" + (y) + "-" + (x + 1)),false,level + 1);
open($("#" + (y) + "-" + (x - 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1);
} else {
me.html("<img src='img/0.bmp'>");
let tmp = $("#" + y + "-" + x);
if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1)
return;
if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 ||
chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1
){
return;
}
open($("#" + (y - 1) + "-" + (x)),false,level + 1);
open($("#" + (y + 1) + "-" + (x)),false,level + 1);
open($("#" + (y) + "-" + (x + 1)),false,level + 1);
open($("#" + (y) + "-" + (x - 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1);
}
}
仔细阅读以上代码,可以发现还有两个函数未实现: update与dieShow。
先啃软柿子,编写update的代码:
function update() {
surplusNum += "";
if (surplusNum.length == 2)
surplusNum = "0" + surplusNum;
if (surplusNum.length == 1)
surplusNum = "00" + surplusNum;
if (surplusNum.length == 0)
surplusNum = "000";
$("#b-h").attr("src","img/d" + surplusNum.charAt(0) + ".bmp");
$("#b-t").attr("src","img/d" + surplusNum.charAt(1) + ".bmp");
$("#b-o").attr("src","img/d" + surplusNum.charAt(2) + ".bmp");
surplusNum *= 1;
}
至于dieShow的代码,可以通过遍历存储雷区的数组编写:
function dieShow() {
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
let tmp = $("#" + i + "-" + j);
if (chess[i][j] == -1){// have boom
if (tmp.html().search(/blood/g) != -1)
continue;
tmp.html("<img src='img/boom.bmp'/>");
} else if (tmp.html().search(/flag/g) != -1 && chess[i][j] != -1){// not have boom and user is marked
tmp.html("<img src='img/error.bmp'/>");
} else if (chess[i][j] > 0){
me.html(chess[i][j]);
tmp.css({
"color": styles[chess[i][j]],
"background-image": "url(\"img/0.bmp\")"
});
} else {
tmp.html("<img src='img/0.bmp'/>");
}
}
}
}
再编写点击按钮重来的代码
$("#start").click(function () {
$(this).attr("src","img/face_normal.bmp");
die = false;
init();
});
这时测试,游戏就基本完成了...等等,为什么右击无法标记?
因为我们忘写了一个重要而简洁的事件响应函数
$(".block").bind("contextmenu", function(){
return false;
});
最后js部分全部代码如下:
var chess = [];
const num = 100;
var surplusNum = num;
var styles = [
"#00f",
"#0f0",
"#f00",
"#08f",
"#f30",
"#0fa",
"#943",
"#eee"
];
var die = false;
var chessJq = $("#chess");
var chessLength = 25;
init();
function init() {
if (num > Math.pow(chessLength,2))
return;
$("#chess").css({
"width": chessLength * 30,
"height": chessLength * 30
});
for (let i = 0 ; i < chessLength ; i++){
chess[i] = [];
for (let j = 0 ; j < chessLength ; j++){
chess[i][j] = 0;
}
}
for (let i = 0 ; i < num ; i++){
while (true){
var x = Math.floor(Math.random() * chess.length),y = Math.floor(Math.random() * chess.length);
if (chess[y][x] == 0){
chess[y][x] = -1;
break;
}
}
}
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
if (chess[i][j] == -1)
continue;
chess[i][j] += get(i - 1,j);
chess[i][j] += get(i + 1,j);
chess[i][j] += get(i,j - 1);
chess[i][j] += get(i,j + 1);
chess[i][j] += get(i - 1,j - 1);
chess[i][j] += get(i + 1,j + 1);
chess[i][j] += get(i + 1,j - 1);
chess[i][j] += get(i - 1,j + 1);
}
}
chessJq.empty();
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
// chessJq.append("<div class='block' id='" + i + "-" + j + "' style='color: " + styles[chess[i][j] - 1] + "'></div>");
// if (chess[i][j] > 0){
// $("#" + i + "-" + j).html(chess[i][j]);
// }
chessJq.append("<div class='block' id='" + i + "-" + j + "'></div>");
}
}
$(".block").mousedown(function (e) {
if (die)
return;
var me = $(this);
if (e.which == 1){// left click
open(me,true,0);
} else {// right click
if (me.html().search(/0/g) !== -1){
me.html("<img src='img/flag.bmp'/>");
surplusNum--;
update();
} else if (me.html().search(/flag/g) !== -1) {
me.html("<img src='img/ask.bmp'/>");
surplusNum++;
update();
} else {
me.html("<img src='img/0.bmp'>");
}
if (surplusNum == 0){
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
if (chess[i][j] == -1 && $("#" + i + "-" + j).html().search("flag") == -1){
die = true;
break;
}
}
}
if (die){
$("#start").attr("src","img/face_fail.bmp");
dieShow();
} else {
$("#start").attr("src","img/face-win.bmp");
}
}
}
});
$(".block").bind("contextmenu", function(){
return false;
});
surplusNum = num;
update();
}
function dieShow() {
for (let i = 0 ; i < chess.length ; i++){
for (let j = 0 ; j < chess.length ; j++){
let tmp = $("#" + i + "-" + j);
if (chess[i][j] == -1){// have boom
if (tmp.html().search(/blood/g) != -1)
continue;
tmp.html("<img src='img/boom.bmp'/>");
} else if (tmp.html().search(/flag/g) != -1 && chess[i][j] != -1){// not have boom and user is marked
tmp.html("<img src='img/error.bmp'/>");
} else if (chess[i][j] > 0){
me.html(chess[i][j]);
tmp.css({
"color": styles[chess[i][j]],
"background-image": "url(\"img/0.bmp\")"
});
} else {
tmp.html("<img src='img/0.bmp'/>");
}
}
}
}
function open(me,canBoom,level) {
var id = me.attr("id");
var tmp = id.split("-");
var x = tmp[1] * 1;
var y = tmp[0] * 1;
if (level > 5){
return;
}
if (me.html().search(/flag/g) != -1 || me.html().search(/ask/g) != -1)
return;
if (chess[y][x] == -1 && canBoom){
me.html("<img src='img/blood.bmp'/>");
die = true;
$("#start").attr("src","img/face_fail.bmp");
dieShow();
} else if (chess[y][x] > 0){
me.html(chess[y][x]);
me.css({
"color": styles[chess[y][x]],
"background-image": "url(\"img/0.bmp\")"
});
let tmp = $("#" + y + "-" + x);
if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1)
return;
if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 ||
chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1
){
return;
}
open($("#" + (y - 1) + "-" + (x)),false,level + 1);
open($("#" + (y + 1) + "-" + (x)),false,level + 1);
open($("#" + (y) + "-" + (x + 1)),false,level + 1);
open($("#" + (y) + "-" + (x - 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1);
} else {
me.html("<img src='img/0.bmp'>");
let tmp = $("#" + y + "-" + x);
if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1)
return;
if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 ||
chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1
){
return;
}
open($("#" + (y - 1) + "-" + (x)),false,level + 1);
open($("#" + (y + 1) + "-" + (x)),false,level + 1);
open($("#" + (y) + "-" + (x + 1)),false,level + 1);
open($("#" + (y) + "-" + (x - 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1);
open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1);
open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1);
}
}
function get(i,j) {
if (i < 0 || i >= chess.length || j < 0 || j >= chess.length)
return 0;
if (chess[i][j] == -1)
return 1;
return 0;
}
function update() {
surplusNum += "";
if (surplusNum.length == 2)
surplusNum = "0" + surplusNum;
if (surplusNum.length == 1)
surplusNum = "00" + surplusNum;
if (surplusNum.length == 0)
surplusNum = "000";
$("#b-h").attr("src","img/d" + surplusNum.charAt(0) + ".bmp");
$("#b-t").attr("src","img/d" + surplusNum.charAt(1) + ".bmp");
$("#b-o").attr("src","img/d" + surplusNum.charAt(2) + ".bmp");
surplusNum *= 1;
}
$("#start").click(function () {
$(this).attr("src","img/face_normal.bmp");
die = false;
init();
});
[完]
点击查看更多内容
16人点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦