如何用JavaScript和canvas技术实现一个长尾词扫雷游戏?

2026-04-02 22:181阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3041个文字,预计阅读时间需要13分钟。

如何用JavaScript和canvas技术实现一个长尾词扫雷游戏?

原文示例:本文字例为大众分享了用js+canvas实现扫雷游戏的整体代码,供大家参考。记录js学习后制作的第一关小游戏。这里的代码还不够精简,让多地方方偷懒没有进行封装,逻辑也有许许待完善。

改写后:本文分享了一个基于js和canvas实现的扫雷游戏整体代码示例,便于学习交流。记录了学习js后制作的第一款小游戏。代码尚需精简,缺乏封装,逻辑亦有待完善。

本文实例为大家分享了用js+canvas实现扫雷游戏的具体代码,供大家参考,具体内容如下

记录js学习后制作的第一关小游戏。

这里的代码还不够精简,许多地方偷懒没有封装,逻辑也有许多可以优化。

<body>       胜利条件,找出所有地雷并标记     <form action="javaScript:createContent()">         <div id="message" style="color: red; display: none;">地雷数量必须小于地图大小xy的平方</div>         <br />          地图大小xy :<input id="xyNum" type="number" required="true" name="points" min="1" max="50"  />          booNum:<input id="booNum" type="number" required="true" name="points" min="1" max="2500"/>         <input type="submit" value="OK" : />         <br /> 1. 输入宽度 <br />2. 输入地雷数(地雷数小于宽*宽) <br /> 3. 单击确定  <br />         鼠标右键:<br />         第一次:标记您的猜测<br />         第二次: 取消标签<br />     </form>     <div id= 'game'>       </div>     <script src="./js/MarkObs.js"></script>     <script src="./js/Isboo.js"></script>     <script src="./js/lei.js"></script>     <script>     let xy = document.getElementById('xyNum');     let boo = document.getElementById('booNum');     let meg = document.getElementById("message");     let div = document.getElementById('game');       //获取输入的宽高和地雷数     createContent = function (){             // console.log(xy.value);             // console.log(boo.value);             let xyNum = xy.value;              let booNum = boo.value;              // console.log(Math.pow(xyNum,2));                          //判断输入是否合法             if(Math.pow(xyNum,2)<boo.value){                 meg.style.display = 'block';             }             else {//绘制地图                 div.innerHTML = '';//清除上次div里的地图                 let game = new Game('game',xyNum,booNum);             }         }     </script> </body>

lei.js

/* 一个自定义原型数组方法  可以放到html里 二维数组查找 arr:要找数组第一第二项 找到返回下标,没有返回-1 PS:只要this数组和arr数组第一第二项的值相等,即为找到。 */ Array.prototype.myindexOf = function(arr){     for(let i=0;i<this.length;i++){                  if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){             return i;         }     }     return -1; } /* 初始化地雷图 id:传入绘制地图的容器id xyNum:长||宽的格子数(地图固定正方形) booNum:地雷数 */  class Game {     constructor(id,xyNum,booNum){         this.xyNum = xyNum;         this.booNum = booNum;         this.id = id;           this.booArrs = [];//保存雷的位置         this.boox = -1;//地雷在x轴第几个块         this.booy = -1;//地雷在x轴第几个块           this.numArrs = [];//保存提醒数字的位置以及数字         this.num = 0;//保存找到的提醒数字的个数           this.markArrs = [];//保存标记位置的数组           //单个块的宽高         this.divw = 20;           // 初始化画布         this.initCanvas(xyNum);         // 初始化地雷位置(地雷用-1代替,图片绘制麻烦)         this.initBooxy(xyNum,booNum);         // 初始化遮挡物         this.initObs(xyNum);           //判断是否胜利         this.win();            }     /*初始化画布(包括网格)     xyNum:传入需要绘制的宽格子数     */      initCanvas(xyNum){         this.canvas = document.createElement('canvas');         this.ctx = this.canvas.getContext('2d');                  //1为border         this.canvas.width = (this.divw+1)*xyNum;         this.canvas.height = (this.divw+1)*xyNum;           // 绘制网格坐标                 // 获取canvas的宽高;                 let w = this.canvas.width;                 let h = this.canvas.height;                 // 绘制水平线                 for (let i = 1; i < h / 21; i++) {                     this.ctx.beginPath();                     this.ctx.lineTo(0,  21 * i) //起点                     this.ctx.lineTo(w, 21 * i); //重点                     this.ctx.stroke();                          }                 // h绘制垂直线                 for (let i = 1; i < w / 21; i++) {                     this.ctx.beginPath();                     this.ctx.lineTo(21 * i,0) //起点                     this.ctx.lineTo(21 * i,h); //重点                     this.ctx.stroke();                          }                 // ctx.stroke();           // 放入容器         this.div = document.getElementById(this.id);         this.div.appendChild(this.canvas);                  // 绑定点击事件!!!         this.canvas.addEventListener('mousedown',this.mouseDown.bind(this))//!!!!注意需要更改this指向,用bind                  // 清除鼠标右键的默认事件 “contextmenu“         this.canvas.addEventListener("contextmenu",function(event){             event.preventDefault()         })     }       /*初始化地雷(包括提醒数字)     xyNum:传入地图的宽的格子数     booNum:传入地雷数     */      initBooxy (xyNum,booNum){           // 随机地雷位置 并保存起来         for(let i=0;i<booNum;i++){               // x,y为地雷所在格子坐标,从0开始             this.boox = parseInt(Math.random()*xyNum);             this.booy = parseInt(Math.random()*xyNum);               //避免雷的位置重复             while(this.booArrs.myindexOf([this.boox,this.booy])!=-1){                 this.boox = parseInt(Math.random()*xyNum);                 this.booy = parseInt(Math.random()*xyNum);             }               this.booArrs.push([this.boox,this.booy])//!!!保存地雷的位置             console.log(i,'x:'+this.boox,'y:'+this.booy);               //绘制地雷             this.ctx.beginPath();//不清楚可不可以删             this.ctx.rect(this.boox*21,this.booy*21,20,20);             this.ctx.fillStyle = 'red';             this.ctx.fill();         }           // 绘制地雷位置周围提醒数字             // 这里的逻辑可以优化,不提前绘制数字,在点击清除障碍物后再判断绘制。             /*             想法一:在每个雷周围添加数字1,如果在多个雷交集处累加             想法二:所有块依次判断周围是否有雷,有几个雷,就fillText()多少             想法三:(一二结合)先找每个雷,该雷周围的8个块依次 判断周围有几个雷         */              // 这里为法二        for(let i=0;i<xyNum;i++){            for(let j=0;j<xyNum;j++){                let num = 0;//提醒数字 ,每次重置为0                              if(this.booArrs.myindexOf([i-1,j-1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i-1,j]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i-1,j+1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i,j-1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i,j+1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i+1,j-1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i+1,j]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i+1,j+1]) !=-1){                     num++;                 }                                 //绘制提醒数字                   if(num!=0 && (this.booArrs.myindexOf([i,j]) ==-1 )){//(this.booArrs.myindexOf([i,j]) ==-1)地雷不标注提示数字若。要标注需要+1(本身)                   this.ctx.font = '18px fasdg'                 this.ctx.fillStyle = '#000'                 this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标                                  this.numArrs.push([i,j,num]);//i,j为提醒数字的块坐标,num为装数组里的值(myindexOf来判断)                 }                 // this.NUM = num;            }        }                         }       /*初始化遮挡物      xyNum:传入地图的宽的格子数     */     initObs(xyNum){     for(let i=0;i<xyNum;i++){         for(let j=0;j<xyNum;j++){               this.ctx.beginPath();             this.ctx.rect(i*21,j*21,20,20);             // this.ctx.fillStyle = 'rgb(155,25,205,0.7)';//设置障碍物透明度可以方便查看雷的位置             this.ctx.fillStyle = 'rgb(155,25,205,1)';//正常游戏时透明度为'1‘             this.ctx.fill();         }     }    }     /*点击事件在initCanvas中绑定*/      mouseDown(){       //这里使用preventDefault,默认事件被没有消除,是因为触发鼠标右键的默认事件的事件类型不是mousedown,是contextmenu     // event.preventDefault(); //ie9以下不兼容           this.clix = Math.floor(event.layerX/( this.divw+1));//this.divw为20是块的宽     this.cliy = Math.floor(event.layerY/( this.divw+1));        // 鼠标左键     if(event.button==0){         this.clearObs(this.clix,this.cliy);         }          // 鼠标右键     else if(event.button==2){                           this.markObs(this.clix,this.cliy);     }        }        /*扫雷*/  //这里的代码可以封装一下 为了方便此处没有封装    clearObs(x,y){     // console.log(x,y);点击坐标       this.ctx.clearRect(x*21,y*21,20,20);//清除指定块          // 点击到标记,点击到提醒数字,点击到地雷,点击到空白,     if(this.markArrs.myindexOf([x,y])!=-1){  //点击到标记,重新覆盖         this.ctx.rect(x*21,y*21,20,20);         this.ctx.fillStyle = 'rgb(155,25,205,1)';         this.ctx.fill();                  this.ctx.beginPath();         this.ctx.fillStyle = 'red';         this.ctx.fillText('?',x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);         this.ctx.fill();       }     else if(this.numArrs.myindexOf([x,y])!=-1){//点击到提醒数字         let index = this.numArrs.myindexOf([x,y]);//下标         let num = this.numArrs[index][2];//提醒数字         this.ctx.fillText(num,x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标         this.num++;     }     else if(this.booArrs.myindexOf([x,y])!=-1){//,点击到地雷,全部绘制         console.log(this.booArrs.myindexOf([x,y]));             //绘制全图             // 绘制提醒数字             for(let i=0;i<this.xyNum;i++){                 for(let j=0;j<this.xyNum;j++){                     let num = 0;//提醒数字 ,每次重置为0                      // if(booArrs.indexof([i-1,j-1]) != -1){//数组是对象这样永远-1                      this.ctx.clearRect(i*21,j*21,20,20);                      if(this.booArrs.myindexOf([i-1,j-1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i-1,j]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i-1,j+1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i,j-1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i,j+1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i+1,j-1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i+1,j]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i+1,j+1]) !=-1){                          num++;                      }                                                                       //绘制提醒数字                      if(num!=0 && (this.booArrs.myindexOf([i,j]) ==-1 )){//(this.booArrs.myindexOf([i,j]) ==-1)地雷不标注提示数字若要标注需要+1(本身)                            this.ctx.font = '18px fasdg'                      this.ctx.fillStyle = '#000'                      this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标                                            this.numArrs.push([i,j,num]);//i,j为提醒数字的块坐标,num为装数组里的值(myindexOf来判断)                      }                      // this.NUM = num;                 }             }             // 绘制地雷             for(let i=0;i<this.booArrs.length;i++){                 this.ctx.fillStyle = 'red';                 this.ctx.rect(this.booArrs[i][0]*21,this.booArrs[i][1]*21,20,20);                 this.ctx.fill();              }             this.ctx.clearRect((this.xyNum-1)*21,(this.xyNum-1)*21,20,20);//每次最后一个都会变红,不知道原因,此处专门删除。                         alert('你惊动了雷雷');                    }       else {           this.isboo(this.ctx,x,y,this.booArrs,this.numArrs,this.markArrs,this.xyNum);         }     }      win (){//标记数组==地雷数组     this.tim = setInterval(()=>{         if(this.booArrs.length ==this.markArrs.length){             for(let i=0;i<this.booNum;i++){                                  if( true == this.booArrs.some(()=>{                     return this.markArrs.myindexOf(this.booArrs[i])!=-1;                 })){                    this.booNum--;                 }                 if(this.booNum==0){                     clearInterval(this.tim);                     alert('you are win');                     }             }         }     },10)      }    isboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum){        new Isboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum);    }         /*标记      */    markObs(x,y){          console.log(x,y);     new MarkObs(this.ctx,x,y,this.booArrs,this.divw,this.markArrs);           }       }

isboo.js

Array.prototype.myindexOf = function(arr){     for(let i=0;i<this.length;i++){                  if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){             return i;         }     }     return -1; } /* 这里解决点击到空白格子时,把周围的空白格一起显示。此处的逻辑可以再优化. ctx:布局 x,点击位置 y,点击位置 booArrs:炸弹的位置数组 numArrs:提示数的位置 markArrs:标记的位置 */  class Isboo {     constructor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         this.x = x;         this.y = y;                  // 判断有没有提醒数字         this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);     }     isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(x<xyNum)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             x+=1;             this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         }else {             return ;         }     }     isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(x>=0)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             x-=1;             // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         }else {             return ;         }     }     isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(y<xyNum)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             y+=1;             // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);           }else {             return ;         }     }     isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(y>=0)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             y-=1;             // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         }else {             return ;         }     }   }

MarkObs.js

Array.prototype.myindexOf = function(arr){     for(let i=0;i<this.length;i++){                  if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){             return i;         }     }     return -1; } /* ctx:布局 x,点击位置 y,点击位置 booArrs:炸弹的位置数组 divw:各自宽度 markarrs:标记数组 */  class MarkObs{     constructor(ctx,x,y,booArrs,divw,markarrs){         this.markObs(ctx,x,y,booArrs,divw,markarrs);     }       markObs(ctx,x,y,booArrs,divw,markarrs){           if(markarrs.myindexOf([x,y])==-1){//如果标记数组里没有该地址,则标记,并添加进数组         ctx.beginPath();         ctx.fillStyle = 'red';         ctx.fillText('?',x*(divw+1)+2,(y+1)*(divw+1)-2);         markarrs.push([x,y]);         }else {//如果标记数组里有该地址,则取消标记,并从数组中删除             ctx.clearRect(x*(divw+1),y*(divw+1),divw,divw);             ctx.beginPath();             ctx.rect(x*21,y*21,20,20);             ctx.fillStyle = 'rgb(155,25,205,1)';             ctx.fill();             markarrs.splice((markarrs.myindexOf([x,y])),1);         }     }   }

页面效果

初始化障碍物设置了透明度时

正常游戏时

这里点击右键标记后忘了把填充颜色设置回来。所以后面变红。

如何用JavaScript和canvas技术实现一个长尾词扫雷游戏?

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。

本文共计3041个文字,预计阅读时间需要13分钟。

如何用JavaScript和canvas技术实现一个长尾词扫雷游戏?

原文示例:本文字例为大众分享了用js+canvas实现扫雷游戏的整体代码,供大家参考。记录js学习后制作的第一关小游戏。这里的代码还不够精简,让多地方方偷懒没有进行封装,逻辑也有许许待完善。

改写后:本文分享了一个基于js和canvas实现的扫雷游戏整体代码示例,便于学习交流。记录了学习js后制作的第一款小游戏。代码尚需精简,缺乏封装,逻辑亦有待完善。

本文实例为大家分享了用js+canvas实现扫雷游戏的具体代码,供大家参考,具体内容如下

记录js学习后制作的第一关小游戏。

这里的代码还不够精简,许多地方偷懒没有封装,逻辑也有许多可以优化。

<body>       胜利条件,找出所有地雷并标记     <form action="javaScript:createContent()">         <div id="message" style="color: red; display: none;">地雷数量必须小于地图大小xy的平方</div>         <br />          地图大小xy :<input id="xyNum" type="number" required="true" name="points" min="1" max="50"  />          booNum:<input id="booNum" type="number" required="true" name="points" min="1" max="2500"/>         <input type="submit" value="OK" : />         <br /> 1. 输入宽度 <br />2. 输入地雷数(地雷数小于宽*宽) <br /> 3. 单击确定  <br />         鼠标右键:<br />         第一次:标记您的猜测<br />         第二次: 取消标签<br />     </form>     <div id= 'game'>       </div>     <script src="./js/MarkObs.js"></script>     <script src="./js/Isboo.js"></script>     <script src="./js/lei.js"></script>     <script>     let xy = document.getElementById('xyNum');     let boo = document.getElementById('booNum');     let meg = document.getElementById("message");     let div = document.getElementById('game');       //获取输入的宽高和地雷数     createContent = function (){             // console.log(xy.value);             // console.log(boo.value);             let xyNum = xy.value;              let booNum = boo.value;              // console.log(Math.pow(xyNum,2));                          //判断输入是否合法             if(Math.pow(xyNum,2)<boo.value){                 meg.style.display = 'block';             }             else {//绘制地图                 div.innerHTML = '';//清除上次div里的地图                 let game = new Game('game',xyNum,booNum);             }         }     </script> </body>

lei.js

/* 一个自定义原型数组方法  可以放到html里 二维数组查找 arr:要找数组第一第二项 找到返回下标,没有返回-1 PS:只要this数组和arr数组第一第二项的值相等,即为找到。 */ Array.prototype.myindexOf = function(arr){     for(let i=0;i<this.length;i++){                  if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){             return i;         }     }     return -1; } /* 初始化地雷图 id:传入绘制地图的容器id xyNum:长||宽的格子数(地图固定正方形) booNum:地雷数 */  class Game {     constructor(id,xyNum,booNum){         this.xyNum = xyNum;         this.booNum = booNum;         this.id = id;           this.booArrs = [];//保存雷的位置         this.boox = -1;//地雷在x轴第几个块         this.booy = -1;//地雷在x轴第几个块           this.numArrs = [];//保存提醒数字的位置以及数字         this.num = 0;//保存找到的提醒数字的个数           this.markArrs = [];//保存标记位置的数组           //单个块的宽高         this.divw = 20;           // 初始化画布         this.initCanvas(xyNum);         // 初始化地雷位置(地雷用-1代替,图片绘制麻烦)         this.initBooxy(xyNum,booNum);         // 初始化遮挡物         this.initObs(xyNum);           //判断是否胜利         this.win();            }     /*初始化画布(包括网格)     xyNum:传入需要绘制的宽格子数     */      initCanvas(xyNum){         this.canvas = document.createElement('canvas');         this.ctx = this.canvas.getContext('2d');                  //1为border         this.canvas.width = (this.divw+1)*xyNum;         this.canvas.height = (this.divw+1)*xyNum;           // 绘制网格坐标                 // 获取canvas的宽高;                 let w = this.canvas.width;                 let h = this.canvas.height;                 // 绘制水平线                 for (let i = 1; i < h / 21; i++) {                     this.ctx.beginPath();                     this.ctx.lineTo(0,  21 * i) //起点                     this.ctx.lineTo(w, 21 * i); //重点                     this.ctx.stroke();                          }                 // h绘制垂直线                 for (let i = 1; i < w / 21; i++) {                     this.ctx.beginPath();                     this.ctx.lineTo(21 * i,0) //起点                     this.ctx.lineTo(21 * i,h); //重点                     this.ctx.stroke();                          }                 // ctx.stroke();           // 放入容器         this.div = document.getElementById(this.id);         this.div.appendChild(this.canvas);                  // 绑定点击事件!!!         this.canvas.addEventListener('mousedown',this.mouseDown.bind(this))//!!!!注意需要更改this指向,用bind                  // 清除鼠标右键的默认事件 “contextmenu“         this.canvas.addEventListener("contextmenu",function(event){             event.preventDefault()         })     }       /*初始化地雷(包括提醒数字)     xyNum:传入地图的宽的格子数     booNum:传入地雷数     */      initBooxy (xyNum,booNum){           // 随机地雷位置 并保存起来         for(let i=0;i<booNum;i++){               // x,y为地雷所在格子坐标,从0开始             this.boox = parseInt(Math.random()*xyNum);             this.booy = parseInt(Math.random()*xyNum);               //避免雷的位置重复             while(this.booArrs.myindexOf([this.boox,this.booy])!=-1){                 this.boox = parseInt(Math.random()*xyNum);                 this.booy = parseInt(Math.random()*xyNum);             }               this.booArrs.push([this.boox,this.booy])//!!!保存地雷的位置             console.log(i,'x:'+this.boox,'y:'+this.booy);               //绘制地雷             this.ctx.beginPath();//不清楚可不可以删             this.ctx.rect(this.boox*21,this.booy*21,20,20);             this.ctx.fillStyle = 'red';             this.ctx.fill();         }           // 绘制地雷位置周围提醒数字             // 这里的逻辑可以优化,不提前绘制数字,在点击清除障碍物后再判断绘制。             /*             想法一:在每个雷周围添加数字1,如果在多个雷交集处累加             想法二:所有块依次判断周围是否有雷,有几个雷,就fillText()多少             想法三:(一二结合)先找每个雷,该雷周围的8个块依次 判断周围有几个雷         */              // 这里为法二        for(let i=0;i<xyNum;i++){            for(let j=0;j<xyNum;j++){                let num = 0;//提醒数字 ,每次重置为0                              if(this.booArrs.myindexOf([i-1,j-1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i-1,j]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i-1,j+1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i,j-1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i,j+1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i+1,j-1]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i+1,j]) !=-1){                     num++;                 }                 if(this.booArrs.myindexOf([i+1,j+1]) !=-1){                     num++;                 }                                 //绘制提醒数字                   if(num!=0 && (this.booArrs.myindexOf([i,j]) ==-1 )){//(this.booArrs.myindexOf([i,j]) ==-1)地雷不标注提示数字若。要标注需要+1(本身)                   this.ctx.font = '18px fasdg'                 this.ctx.fillStyle = '#000'                 this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标                                  this.numArrs.push([i,j,num]);//i,j为提醒数字的块坐标,num为装数组里的值(myindexOf来判断)                 }                 // this.NUM = num;            }        }                         }       /*初始化遮挡物      xyNum:传入地图的宽的格子数     */     initObs(xyNum){     for(let i=0;i<xyNum;i++){         for(let j=0;j<xyNum;j++){               this.ctx.beginPath();             this.ctx.rect(i*21,j*21,20,20);             // this.ctx.fillStyle = 'rgb(155,25,205,0.7)';//设置障碍物透明度可以方便查看雷的位置             this.ctx.fillStyle = 'rgb(155,25,205,1)';//正常游戏时透明度为'1‘             this.ctx.fill();         }     }    }     /*点击事件在initCanvas中绑定*/      mouseDown(){       //这里使用preventDefault,默认事件被没有消除,是因为触发鼠标右键的默认事件的事件类型不是mousedown,是contextmenu     // event.preventDefault(); //ie9以下不兼容           this.clix = Math.floor(event.layerX/( this.divw+1));//this.divw为20是块的宽     this.cliy = Math.floor(event.layerY/( this.divw+1));        // 鼠标左键     if(event.button==0){         this.clearObs(this.clix,this.cliy);         }          // 鼠标右键     else if(event.button==2){                           this.markObs(this.clix,this.cliy);     }        }        /*扫雷*/  //这里的代码可以封装一下 为了方便此处没有封装    clearObs(x,y){     // console.log(x,y);点击坐标       this.ctx.clearRect(x*21,y*21,20,20);//清除指定块          // 点击到标记,点击到提醒数字,点击到地雷,点击到空白,     if(this.markArrs.myindexOf([x,y])!=-1){  //点击到标记,重新覆盖         this.ctx.rect(x*21,y*21,20,20);         this.ctx.fillStyle = 'rgb(155,25,205,1)';         this.ctx.fill();                  this.ctx.beginPath();         this.ctx.fillStyle = 'red';         this.ctx.fillText('?',x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);         this.ctx.fill();       }     else if(this.numArrs.myindexOf([x,y])!=-1){//点击到提醒数字         let index = this.numArrs.myindexOf([x,y]);//下标         let num = this.numArrs[index][2];//提醒数字         this.ctx.fillText(num,x*(this.divw+1)+2,(y+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标         this.num++;     }     else if(this.booArrs.myindexOf([x,y])!=-1){//,点击到地雷,全部绘制         console.log(this.booArrs.myindexOf([x,y]));             //绘制全图             // 绘制提醒数字             for(let i=0;i<this.xyNum;i++){                 for(let j=0;j<this.xyNum;j++){                     let num = 0;//提醒数字 ,每次重置为0                      // if(booArrs.indexof([i-1,j-1]) != -1){//数组是对象这样永远-1                      this.ctx.clearRect(i*21,j*21,20,20);                      if(this.booArrs.myindexOf([i-1,j-1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i-1,j]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i-1,j+1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i,j-1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i,j+1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i+1,j-1]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i+1,j]) !=-1){                          num++;                      }                      if(this.booArrs.myindexOf([i+1,j+1]) !=-1){                          num++;                      }                                                                       //绘制提醒数字                      if(num!=0 && (this.booArrs.myindexOf([i,j]) ==-1 )){//(this.booArrs.myindexOf([i,j]) ==-1)地雷不标注提示数字若要标注需要+1(本身)                            this.ctx.font = '18px fasdg'                      this.ctx.fillStyle = '#000'                      this.ctx.fillText(num,i*(this.divw+1)+2,(j+1)*(this.divw+1)-2);//加1和j+1为测试结果,-+2是为了文本在格子里居中//y为文本中线坐标                                            this.numArrs.push([i,j,num]);//i,j为提醒数字的块坐标,num为装数组里的值(myindexOf来判断)                      }                      // this.NUM = num;                 }             }             // 绘制地雷             for(let i=0;i<this.booArrs.length;i++){                 this.ctx.fillStyle = 'red';                 this.ctx.rect(this.booArrs[i][0]*21,this.booArrs[i][1]*21,20,20);                 this.ctx.fill();              }             this.ctx.clearRect((this.xyNum-1)*21,(this.xyNum-1)*21,20,20);//每次最后一个都会变红,不知道原因,此处专门删除。                         alert('你惊动了雷雷');                    }       else {           this.isboo(this.ctx,x,y,this.booArrs,this.numArrs,this.markArrs,this.xyNum);         }     }      win (){//标记数组==地雷数组     this.tim = setInterval(()=>{         if(this.booArrs.length ==this.markArrs.length){             for(let i=0;i<this.booNum;i++){                                  if( true == this.booArrs.some(()=>{                     return this.markArrs.myindexOf(this.booArrs[i])!=-1;                 })){                    this.booNum--;                 }                 if(this.booNum==0){                     clearInterval(this.tim);                     alert('you are win');                     }             }         }     },10)      }    isboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum){        new Isboo(ctx,x,y,booArrs,numArrs,markArrs,xyNum);    }         /*标记      */    markObs(x,y){          console.log(x,y);     new MarkObs(this.ctx,x,y,this.booArrs,this.divw,this.markArrs);           }       }

isboo.js

Array.prototype.myindexOf = function(arr){     for(let i=0;i<this.length;i++){                  if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){             return i;         }     }     return -1; } /* 这里解决点击到空白格子时,把周围的空白格一起显示。此处的逻辑可以再优化. ctx:布局 x,点击位置 y,点击位置 booArrs:炸弹的位置数组 numArrs:提示数的位置 markArrs:标记的位置 */  class Isboo {     constructor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         this.x = x;         this.y = y;                  // 判断有没有提醒数字         this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);     }     isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(x<xyNum)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             x+=1;             this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         }else {             return ;         }     }     isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(x>=0)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             x-=1;             // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         }else {             return ;         }     }     isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(y<xyNum)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             y+=1;             // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);           }else {             return ;         }     }     isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum){         if((numArrs.myindexOf([x,y])==-1)&&(y>=0)&&(markArrs.myindexOf([x,y])==-1)){             ctx.clearRect(x*21,y*21,20,20);             y-=1;             // this.isbool(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboor(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             // this.isboot(ctx,x,y,booArrs,numArrs,markArrs,xyNum);             this.isboob(ctx,x,y,booArrs,numArrs,markArrs,xyNum);         }else {             return ;         }     }   }

MarkObs.js

Array.prototype.myindexOf = function(arr){     for(let i=0;i<this.length;i++){                  if((this[i][0] == arr[0]) &&(this[i][1]==arr[1])){             return i;         }     }     return -1; } /* ctx:布局 x,点击位置 y,点击位置 booArrs:炸弹的位置数组 divw:各自宽度 markarrs:标记数组 */  class MarkObs{     constructor(ctx,x,y,booArrs,divw,markarrs){         this.markObs(ctx,x,y,booArrs,divw,markarrs);     }       markObs(ctx,x,y,booArrs,divw,markarrs){           if(markarrs.myindexOf([x,y])==-1){//如果标记数组里没有该地址,则标记,并添加进数组         ctx.beginPath();         ctx.fillStyle = 'red';         ctx.fillText('?',x*(divw+1)+2,(y+1)*(divw+1)-2);         markarrs.push([x,y]);         }else {//如果标记数组里有该地址,则取消标记,并从数组中删除             ctx.clearRect(x*(divw+1),y*(divw+1),divw,divw);             ctx.beginPath();             ctx.rect(x*21,y*21,20,20);             ctx.fillStyle = 'rgb(155,25,205,1)';             ctx.fill();             markarrs.splice((markarrs.myindexOf([x,y])),1);         }     }   }

页面效果

初始化障碍物设置了透明度时

正常游戏时

这里点击右键标记后忘了把填充颜色设置回来。所以后面变红。

如何用JavaScript和canvas技术实现一个长尾词扫雷游戏?

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。