最近看完了视频贪吃蛇和扫雷,都是非常经典的游戏,且代码较为简单,接下来记录上扫雷代码的过程。
先截个图,看看效果:
首先html代码:
接下来是css代码:
*{ /* 规范代码的习惯,去掉margin和padding的默认值 */
margin: 0;
padding: 0;
}
.wrapper{ /* 承载界面的设置 */
width: 100%; /* 100%的宽度 */
height: 630px; /* 按照自己电脑的浏览器设置的高度 */
position: absolute; /* 绝对定位 */
left: 0;
top: 0;
}
.box{ /* 游戏主界面 */
width: 300px; /* 设置一个300*300的正方形 */
height: 300px;
border: 1px solid black; /* 边框 */
position: absolute; /* 这到底表示的是基于父级定位的中心定位 */
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
}
.alertBox{ /* 游戏结束后的承载界面 */
display: none; /* 游戏开始不显示,在js中触发后显示 */
position: absolute; /* 绝对定位 */
left: 0;
top: 0;
width: 100%; /* 设置宽高 */
height: 100%;
background-color: rgba(0, 0, 0, 0.2); /* 给承载界面一个背景颜色和透明度 */
}
.alertImg{ /* 游戏结束后出现的提示框 */
position: absolute; /* 基于父级定位的中心定位 */
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
background-image: url('img/success.png'); /* 设置提示的图片 */
background-size: 100% 100%;
width: 300px; /* 设置图片的宽高 */
height: 200px;
}
.close{ /* 关闭按钮 */
background-image: url('img/shanchu.png'); /* 关闭按钮图片 */
background-size: 100% 100%;
width: 30px; /* 设置宽高 */
height: 30px;
position: absolute; /* 基于父级的绝对定位 */
top: 0;
right: 0;
cursor: pointer; /* 当鼠标移动到该图片上面时,变为小手 */
}
上述的css代码还未完整,需要结合js里新建的div中设置class或id后,再补充。
接下来js:
var box = document.getElementById('box'); //获取到html中的id = ‘box’的节点,下面相同
var minesNum;
var mineOver;
var mineMap = [];
var block;
var closeBtn = document.getElementById('close');
var alertBox = document.getElementById('alertBox');
var alertImg = document.getElementById('alertImg');
bindEvent(); //触发bindEvent函数
function bindEvent(){
init(); //触发init函数
box.oncontextmenu = function(){ //取消box里的右键默认功能
return false;
}
box.onmousedown = function(e){ //当box里被鼠标按键触发时
var event = e.target; //event获取到按键的目标
if(e.which == 1){ //e.which = 1表示鼠标左键
leftClick(event); //触发该函数,携带event
}else if(e.which == 3){ //e.which = 3表示鼠标的右键
rightClick(event); //同上
}
}
closeBtn.onclick = function(){ //游戏结束后的图片右上角的图片触发的事件
alertBox.style.display = 'none'; //游戏结束的提示图片消失
box.innerHTML = ''; //去除掉玩过游戏后的剩余界面
init(); //重新触发游戏开始界面,开始新的一轮游戏
}
}
function init(){ //游戏主界面的内容
minesNum = 10;
mineOver = 10;
for(var i = 0; i < 10;i ++){ //循环10次
for(var j = 0; j < 10;j ++){ //加上面的10次,循环100次,生成100个格子
var con = document.createElement('div'); //生成格子
con.classList.add('block'); //对格子添加class = ‘block’
con.setAttribute('id',i+'-'+j); //对每个格子添加不同的id = ‘i-j’(这里的i,j表示横纵格子的数字,如1-3表示第二行第四列,注这里的数字从0开始算)
box.appendChild(con); //html中的box显示出来con内容(将100*100格子显示在html中)
mineMap.push({mine:0}); //每次生成小格子往数组里面传, 传一个参数mine 初始值0
}
}
block = document.getElementsByClassName('block'); //得到class = ‘block’的节点,就是上面的小格子
while(minesNum){
var mineIndex = Math.floor(Math.random()*100); //得到0-100中的随机数字
if(mineMap[mineIndex].mine === 0){ //找到随机位置,且该位置初始时mine为0
mineMap[mineIndex].mine = 1; //防止同一位置重复生成雷
block[mineIndex].classList.add('isLei'); //随机出现雷的标记
minesNum --; //该游戏中限制共10个雷,循环10次,埋10个雷
}
}
}
function leftClick(dom){ //左点击事件
if(dom.classList.contains('flag')){ //当标记过旗子后不可左点击
; //不执行任何事件
}else{
var isLei = document.getElementsByClassName('isLei'); //得到class = ‘isLei’的节点
if(dom && dom.classList.contains('isLei')){ // 判断点击的是雷 contains返回布尔值,判断指定的类名是否存在。
for(var i = 0;i < isLei.length;i ++){ //循环雷总数的次数,将所有的雷全部显示出来
isLei[i].classList.add('show'); //点出后的雷添加上class = ‘show’
}
setTimeout(function(){
alertBox.style.display = 'block'; //出现游戏结束的界面
alertImg.style.backgroundImage = 'url("img/over.png")'; //游戏界面输了的图片
},800); //游戏失败后,800ms后出现上述事件
}else{ //点击的不是雷时,触发的事件
var n = 0;
var posArr = dom && dom.getAttribute('id').split('-'); //得到按键目标上的格子的id值,取掉中间的-符号
var posX = posArr && +posArr[0]; //得到目标格子上的第一个数字
var posY = posArr && +posArr[1]; //得到目标格式上的第二个数字
dom && dom.classList.add('num'); //为目标格子添加上class = ‘num’
for(var i = posX - 1;i <= posX + 1;i ++){ //循环目标自己和左右三个格子
for(var j = posY - 1; j <=posY + 1;j ++ ){ //循环目标格子自己和上下三个格子,共循环9次
var aroundBox = document.getElementById(i+'-'+j); //得到di = ‘i-j’的节点,就是得到目标格子上下左右9个格子
if(aroundBox && aroundBox.classList.contains('isLei')){ //判断目标格子和周围是否有雷
n ++; //目标格子周围有一个雷就+1
}
}
}
if(n != 0){ //当n不等于0时,显示出对应周围格子有雷个数情况
dom && (dom.innerHTML = n);
}else{ //等于0表示周围没有雷
dom && (dom.innerHTML = ''); //没有雷,用空显示
}
if(n == 0){ //当n为0时,还需要继续判断它周围的周围是否有雷
for(var i = posX - 1 ;i <= posX + 1;i ++){ //同上循环目标格子的周围9个(包括自己),表示9次循环
for(var j = posY - 1;j <= posY + 1;j ++){
var nearBox = document.getElementById(i + '-' + j); //得到格子上的id
if(nearBox && nearBox.length != 0){ //判断目标格子长度是否为0(即目标有没有周围的格子,有才能接着判断),不为0时才执行下列事件
if(!nearBox.classList.contains('check')){ //当格子上没有class = ‘check’时执行下列事件
nearBox.classList.add('check'); //为该格子加上class = ‘check’
leftClick(nearBox); //再执行一次左击事件函数
}
}
}
}
}
if(document.getElementsByClassName('num').length == 90){ //判断被点击出的class = ‘num’的个数,由于该游戏时100*100的界面,且共有10个雷,即有90个num,当都被点击开后且没有触发到雷,即游戏赢了,所以触发下面的事件
alertBox.style.display = 'block';
alertImg.style.backgroundImage = 'url("img/success.png")'; //出现游戏赢了的图片
}
}
}
}
function rightClick(dom){ //右键事件函数
if(dom.classList.contains('num')){ //当右击的是已经被点开的格子,表示没反应,不执行任何事件
return;
}
dom.classList.toggle('flag'); //给目标格子交替加入class = flag,点击一次出现,第二次消失,更替
if(dom.classList.contains('isLei') && dom.classList.contains('flag')){ //目标格子有雷(class = ‘isLei’的节点)且有旗子(class = ‘flag’的节点)时触发事件
mineOver --; //雷的数量减少
}
if(!dom.classList.contains('isLei') && dom.classList.contains('flag')){ //没有雷,有旗
mineOver ++; //总显示雷数增加
}
if(dom.classList.contains('isLei') && !dom.classList.contains('flag')){ //有雷,没旗(感觉好像不存在这个语句也可以。。。,但是当你按的右键是第二次时就有用了!)
mineOver ++;
}
if(!dom.classList.contains('isLei') && !dom.classList.contains('flag')){ //没雷,没旗
mineOver --;
}
if(mineOver == 0){ //当所有的雷都被标记旗子后,表示游戏赢了,即出现游戏结束界面
alertBox.style.display = 'block';
alertImg.style.backgroundImage = 'url("img/success.png")';
}
}
补全上述js中创建的class的css代码:`
.block{ //小格子的设置
width: 29px; //设置宽高,记得这里需要算上边框的1px
height: 29px;
border-right: 1px solid #b25f27 ; //右边框
border-bottom: 1px solid #b25f27 ; //下边框
box-shadow: 0 0 4px #333 inset; //加点阴影
background-color: #6493f8; //格子颜色
float: left; //排齐格子
}
.show{ //显示炸弹
background-image: url('img/zd.png');
background-size: 100% 100%;
}
.num{ //显示数字
background: #dddddd; //颜色
font-size: 12px; //字体
font-weight: bold; //加粗
line-height: 29px;
text-align: center; //数字显示正中间
}
.flag{ //显示旗子
background-image: url('img/hq.png');
background-size: 100% 100%;
}