中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何利用js+canvas實現掃雷游戲

發布時間:2022-06-08 14:14:41 來源:億速云 閱讀:145 作者:iii 欄目:開發技術

這篇文章主要介紹“如何利用js+canvas實現掃雷游戲”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“如何利用js+canvas實現掃雷游戲”文章能幫助大家解決問題。

代碼如下

<body>
 
    勝利條件,找出所有地雷并標記
    <form action="javaScript:createContent()">
        <div id="message" >地雷數量必須小于地圖大小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);
        }
    }
 
}

頁面效果

初始化障礙物設置了透明度時

如何利用js+canvas實現掃雷游戲

正常游戲時

這里點擊右鍵標記后忘了把填充顏色設置回來。所以后面變紅。

如何利用js+canvas實現掃雷游戲

關于“如何利用js+canvas實現掃雷游戲”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

谢通门县| 宽甸| 沛县| 清远市| 张掖市| 黔江区| 延津县| 永嘉县| 汉中市| 安远县| 麦盖提县| 乐平市| 忻州市| 西畴县| 辽源市| 宜章县| 兰州市| 滦南县| 无锡市| 甘南县| 威海市| 谷城县| 自治县| 蒙山县| 合山市| 汉寿县| 灵宝市| 博野县| 旬阳县| 宜春市| 基隆市| 绿春县| 杭州市| 环江| 习水县| 东莞市| 慈溪市| 肃南| 大洼县| 阿勒泰市| 乳山市|