js实现消灭星星(web简易版)
作者:qq_40566547
这篇文章主要为大家详细介绍了js实现web简易版的消灭星星,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
昨天看视频之后,整理思路,自己完成了简易版消灭星星
思路:
模块1:初始化
- 初始化总分数、当前分数、背景图、选择的星星分数
- 初始化星星(生成二维数组,对二维数组的每一个对象设置样式(长、宽、背景图),生成二维数组个div元素节点插入到游戏面板中)
模块2:预判
判断:
鼠标移动到某一个方块,判断上下左右是否有连接着的小方块(采用递归方法),然后将其存储到数组choose[],移到其他方块时,choose置为空
闪烁:
将已选中的小方块设置样式(缩放)
显示选择分数:
设置初始分数和递增分数,根据选中的块数算出选中的分数
模块3:点击
消失:
点击已选中的小方块,将连着的所有小方块在二维数组的位置设置为空,清空choose数组
移动:
下移:设置一个指针,指向最下面的行。每当行+1,若遇到不为空的方块,则pointer++,若遇到该列某行为空,则将pointer的行数设为i
左移:最底部的一行若有一列为空,将右边的所有方块的列-1
判断:
每次点击完成之后判断游戏是否结束
代码部分
html
html结构很简单
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="./index.js"></script> <link rel="stylesheet" href="index.css" > </head> <body> <div id="pop_star"> <div id="target_score">目标分数:2000</div> <div id="now_score">当前分数:0</div> <div id="select_score">0块 0分</div> </div> </body> </html>
CSS
css布局也很简单,相信不用我来说
* { margin: 0px; padding: 0px; } html, body { height: 100%; width: 100%; } #pop_star { width: 500px; height: 100%; background: url("./pic/background.png"); margin-left: auto; margin-right: auto; position: relative; background-size: cover; font-size: 0px; } #target_score { width: 100%; height: 50px; line-height: 50px; text-align: center; color: white; font-size: 20px; position: relative; } #now_score { width: 100%; height: 50px; line-height: 50px; text-align: center; color: white; font-size: 20px; position: relative; } #select_score { width: 100%; height: 50px; line-height: 50px; text-align: center; color: white; font-size: 20px; position: relative; opacity: 0; }
JS
/* 创建二维数组 * * * */ var table ; var suqareWidth = 50 ; //一个星星/方块边长 var boardWidth = 10 ; //横竖方块个数 var squareSet = [];//小方块的集合,二维数组 var choose = [];//有相邻的小方块,将其放到这个数组 var timer = null ; var baseScore = 5 ; var stepScore = 10 ; var totalScore = 0 ; var targetScore = 1500; var flag = true ; var tempSquare = null;//在处理鼠标动作过程中,动作被屏蔽,导致事件处理完成,有不连贯现象 function createSquare(value , row , col){ //创建小方块节点 var blocks = document.createElement('div'); //设置样式 blocks.style.width = suqareWidth + 'px'; blocks.style.height = suqareWidth + 'px'; blocks.style.display = 'inline-block'; blocks.style.boxSizing = 'border-box'; blocks.style.position = 'absolute'; blocks.style.borderRadius = "12px"; //小方块的行和列,小方块的num.jpg blocks.num = value ; blocks.row = row ; blocks.col = col ; return blocks; } function refresh(){ for(var i = 0 ; i < squareSet.length ; i ++){ for (var j = 0 ; j < squareSet[i].length ; j++) { //严谨判断 if (squareSet[i][j] == null) { continue; } //将二维数组里面的小方块对应面板的行和列显示 squareSet[i][j].row = i; squareSet[i][j].col = j; //列*方块长度 squareSet[i][j].style.transition = "left 0.3s, bottom 0.3s"; squareSet[i][j].style.left = squareSet[i][j].col * suqareWidth + 'px'; squareSet[i][j].style.bottom = squareSet[i][j].row * suqareWidth + 'px'; //背景图 squareSet[i][j].style.backgroundImage = "url('img/" + squareSet[i][j].num + ".png')"; squareSet[i][j].style.backgroundSize = 'cover'; squareSet[i][j].style.transform = 'scale(0.95)';//是图片缩小至原来的0.95倍 } } } function checkLinked(square , arr){ //严谨判断 if(square == null){ return; } //添加小方块到arr arr.push(square); /* 判断位于该小方块左边的小方格是否能被收录进选择数组 1.小方格不能是最左边的 2.小方格左边必须有小方块 3.小方块左边的要和该小方块颜色相同 4.该小方块左边没有被收录到数组中去 5.递归 * * */ //向左 if(square.col > 0 && squareSet[square.row][square.col - 1] && squareSet[square.row][square.col - 1].num == square.num && arr.indexOf(squareSet[square.row][square.col - 1]) == -1){ checkLinked(squareSet[square.row][square.col - 1] , arr); } //向右 if(square.col < boardWidth - 1 && squareSet[square.row][square.col + 1] && squareSet[square.row][square.col + 1].num == square.num && arr.indexOf(squareSet[square.row][square.col + 1]) == -1){ checkLinked(squareSet[square.row][square.col + 1] , arr); } //向上 if(square.row < boardWidth - 1 && squareSet[square.row + 1][square.col ] && squareSet[square.row + 1][square.col].num == square.num && arr.indexOf(squareSet[square.row + 1][square.col ]) == -1){ checkLinked(squareSet[square.row + 1][square.col] , arr); } //向上 if(square.row > 0 && squareSet[square.row - 1][square.col] && squareSet[square.row - 1][square.col].num == square.num && arr.indexOf(squareSet[square.row - 1][square.col]) == -1){ checkLinked(squareSet[square.row - 1][square.col] , arr); } } //让选中的小方块闪烁 function flicker(arr){ var num = 0 ; //设置计时器,让其一之闪烁 timer = setInterval(function(){ for (var i = 0 ; i < arr.length ; i++) { //设置缩放样式 arr[i].style.border = "3px solid #BFEFFF"; arr[i].style.transform = "scale("+(0.9 + 0.05 *Math.pow(-1 , num))+")"; } //小方块闪烁完成之后num++,使其再次缩放 num++; },300); } function back(){ //若计时器还存在,清楚计数器 if(timer != null){ clearInterval(timer); } //返回原样式 for(var i = 0 ; i < squareSet.length ; i++){ for(var j = 0 ; j < squareSet[i].length ; j++){ //严谨判断 if (squareSet[i][j] == null) { continue; } squareSet[i][j].style.border = "0px solid #BFEFFF"; squareSet[i][j].style.transform = "scale(0.95)"; } } } //选中分数 function selectScore(){ var socre = 0 ; //遍历choose for(var i = 0 ; i < choose.length ; i++){ socre += baseScore + stepScore * i ; } //严谨判断 if (socre <= 0) { return ; } //设置select_score的样式 var select_score = document.getElementById('select_score'); select_score.innerHTML = choose.length + "块" + socre + "分"; select_score.style.transition = null ; //设置透明度,让其突然显示 select_score.style.opacity = 1 ; //让其逐渐消失 setTimeout(function(){ select_score.style.transition = 'opacity 1s'; select_score.style.opacity = 0; },1000); } //鼠标移动到该小方块时,闪烁 function mouseOver(obj){ //当鼠标在移动到该方块突然移动到其他位置时 if(!flag){ tempSquare = obj; return ; } //当鼠标移开选中的方块之后,让其回到原来的样式 back(); //选择相邻相同的小方格 //传一个数组 choose = []; checkLinked(obj , choose);//obj是当前鼠标移到的小方块,choose是存储响铃小方块的数组 if (choose.length <= 1) { choose = [] ; return; } //将选中的设置样式,让其闪烁 flicker(choose); //显示所选中的小方块的分数 selectScore(); } function move(){ /* 1.设置一个指针,开始的时候指针指向最下面一行 2.此时指针和j是否一样,一样都++。 3.若改行该列该列有小方块,均++,反之j++,pointer不变,循环判断该条件 3.当j移动到该列某行的小方块,该小方块存在,则将j指向的小方块的位置设置为指针指向的那一个小方块的位置 * */ //向下移动 for (var i = 0 ; i < boardWidth ; i ++) { var pointer = 0;//pointer指向小方块,当遇到null的时候停止,等待上面的小方块落到这里来 for (var j = 0 ; j < boardWidth ; j ++) { if (squareSet[j][i] != null) { if (j != pointer) { squareSet[pointer][i] = squareSet[j][i]; squareSet[j][i].row = pointer; squareSet[j][i] = null; } pointer ++; } } } //横向移动 for (var i = 0 ; i < squareSet[0].length ; ) { if (squareSet[0][i] == null) { for (var j = 0 ; j < boardWidth ; j ++) { squareSet[j].splice(i, 1); } continue; } i ++; } refresh(); } function isFinish(){ for (var i = 0 ; i < squareSet.length ; i++) { for (var j = 0 ; j < squareSet[i].length ; j++) { //判断周围是否还有可消除的方块 var temp = []; checkLinked(squareSet[i][j] , temp); if(temp.length > 1){ return false ; } } } return true; } function init(){ //获取面板 table = document.getElementById('pop_star'); //创建二维数组 for(var i = 0 ; i < boardWidth ; i++){ squareSet[i] = new Array(); for(var j = 0 ; j < boardWidth; j++){ //创建小方块 var square = createSquare(Math.floor(Math.random() * 5), i, j); //鼠标移动到该方块 square.onmouseover = function(){ mouseOver(this); } //点击小方块时的操作 square.onclick = function(){ //小方块在被点击的时候其他操作不能影响他的执行 if(choose.length == 0 || !flag ){ return ; } flag = false; tempSquare = null ; /* 1.增加当前分数 2.小方块消失 3.向下或想做移动 4.判断游戏是否结束 */ var socre = 0 ; //遍历choose for(var i = 0 ; i < choose.length ; i++){ socre += baseScore + stepScore * i ; } totalScore += socre ;//总分数 //改变样式 document.getElementById('now_score').innerHTML = '当前分数:' + totalScore; //小方块消失 /* 1.从二维数组里面移除选择了的小方块 2.在面板上移除div,不然div会一直占着格子 * */ for(var i = 0 ; i < choose.length ; i++){ //立即函数,立即出发该函数,否则的话,不会执行 (function(i){ setTimeout(function(){ //将二维数组的某一值设置为空,后面的会向前移 squareSet[choose[i].row][choose[i].col] = null ; //移除div table.removeChild(choose[i]); },i * 100); })(i); } //移动 setTimeout(function(){ move(); setTimeout(function(){ var finished = isFinish(); if(finished){ if (totalScore >= targetScore) { alert('闯关成功'); } else{ alert('闯关失败'); } }else{//还可以继续 choose = [] ; flag = true; mouseOver(tempSquare); } } , 300 + choose.length * 150); },choose.length * 100); } //将小方块放进二维数组 squareSet[i][j] = square; //将创建好的小方块插入到面板中 table.appendChild(square); } } //显示小星星,刷新整个面板 refresh(); } //页面加载完成之后,初始化所有操作 window.onload = function(){ init(); }
其实这里还有优化的就是闯关部分,大致的思路就是,游戏每过一关增加目标分数,当游戏结束时,闯关失败,目标分数恢复初始值。
大家有什么不懂,可以在评论区评论。
jq进阶版的源码详情见我github,网址
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。