溫馨提示×

溫馨提示×

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

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

如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲

發(fā)布時間:2021-08-04 09:17:47 來源:億速云 閱讀:128 作者:小新 欄目:web開發(fā)

這篇文章主要為大家展示了“如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲”這篇文章吧。

先看效果圖:


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲

起因

如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲
 

又到深夜了,我按照以往在公眾號寫著數(shù)據(jù)結(jié)構(gòu)!這占用了我大量的時間!我的超越妹妹嚴(yán)重缺乏陪伴而 怨氣滿滿!


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲
 

超越妹妹時常埋怨,認(rèn)為數(shù)據(jù)結(jié)構(gòu)這么抽象難懂的東西沒啥作用,常會問道:天天寫這玩意,有啥作用。而我答道:能干事情多了,比如寫個小游戲啥的!


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲
 

當(dāng)我碼完字準(zhǔn)備睡覺時:寫不好別睡覺!


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲

分析

如果用數(shù)據(jù)結(jié)構(gòu)與算法造出東西來呢?

什么東西簡單容易呢?我百度一下,我靠,這個鳥游戲原來不好搞啊,得接觸一堆不熟悉的東西,搞不來搞不來。

有了(靈光一閃),寫個猜數(shù)字游戲,問他加減乘除等于幾。

超越妹妹又不是小孩子,糊弄不過去。

經(jīng)過一番折騰,終于在半夜12點確定寫迷宮小游戲了。大概弄清楚其中的幾個步驟。

大概是:

畫線—>畫迷宮(擦線)—>方塊移動、移動約束(不出界不穿墻)—>完成游戲。畫線(棋盤)

對于html+js(canvas)畫的東西,之前學(xué)過javaswing應(yīng)該有點映像。在html中有個canvas 的畫布,可以在上面畫一些東西和聲明一些監(jiān)聽(鍵盤監(jiān)聽)。

對于迷宮來說,那些線條是沒有屬性的,只有位置x,y,你操作這個畫布時候,可能和我們習(xí)慣的面相對象思維不一樣。所以,在你設(shè)計的線或者點的時候,記得那個點、線在什么位置,在后續(xù)劃線還是擦線還是移動的時候根據(jù)這個位置進(jìn)行操作。

<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>	
  </head> 
  <body>
  <canvas id="mycanvas" width="600px" height="600px"></canvas>
    
  </body>
  <script type="text/javascript">

var aa=14;
    var chess = document.getElementById("mycanvas");
    var context = chess.getContext('2d');

    //  var context2 = chess.getContext('2d');
    //      context.strokeStyle = 'yellow';
    var tree = [];//存放是否聯(lián)通
    var isling=[];//判斷是否相連
    for(var i=0;i<aa;i++){
        tree[i]=[];
        for(var j=0;j<aa;j++){
            tree[i][j]=-1;//初始值為0
        }
    }  for(var i=0;i<aa*aa;i++){
        isling[i]=[];
        for(var j=0;j<aa*aa;j++){
            isling[i][j]=-1;//初始值為0
        }
    }
    
    function drawChessBoard(){//繪畫
        for(var i=0;i<aa+1;i++){
            context.strokeStyle='gray';//可選區(qū)域
            context.moveTo(15+i*30,15);//垂直方向畫15根線,相距30px;
            context.lineTo(15+i*30,15+30*aa);
            context.stroke();
            context.moveTo(15,15+i*30);//水平方向畫15根線,相距30px;棋盤為14*14;
            context.lineTo(15+30*aa,15+i*30);
            context.stroke();
        }
    }
    drawChessBoard();//繪制棋盤
   
    //      var mymap=new Array(36);
    //      for(var i=0;i<36;i++)
    //     {mymap[i]=-1;}


  </script>
</html>

實現(xiàn)效果


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲

畫迷宮

隨機(jī)迷宮怎么生成?怎么搞?一臉懵逼。

因為我們想要迷宮,那么就需要這個迷宮出口和入口有連通路徑,你可能壓根不知道迷宮改怎么生成,用的什么算法。小聲BB:用并查集(不相交集合)。

迷宮和不相交集合有什么聯(lián)系呢?(規(guī)則)

之前筆者在前面數(shù)據(jù)結(jié)構(gòu)與算法系列中曾經(jīng)介紹過并查集(不相交集合),它的主要功能是森林的合并,不聯(lián)通的通過并查集能夠快速將兩個森林合并,并且能夠快速查詢兩個節(jié)點是否在同一個森林中!

我們的隨機(jī)迷宮:在每個方格都不聯(lián)通的情況下,是一個棋盤方格,這也是它的初始狀態(tài)。而這個節(jié)點可以跟鄰居可能相連,也可能不相連。我們可以通過并查集實現(xiàn)。

具體思路為:(主要理解并查集)

1:定義好不想交集合的基本類和方法(search,union等)
2:數(shù)組初始化,每一個數(shù)組元素都是一個集合,值為-1
3:隨機(jī)查找一個格子(一維數(shù)據(jù)要轉(zhuǎn)換成二維,有點麻煩),在隨機(jī)找一面墻(也就是找這個格子的上下左右),還要判斷找的格子出沒出界。
具體在格子中找個隨機(jī)數(shù)m&mdash;&mdash;>隨機(jī)數(shù)m在二維中的位置[m/長,m%長]&mdash;&mdash;>這個二維的上下左右隨機(jī)找一個位置p[m/長+1,m%長][m/長-1,m%長][m/長,m%長+1][m/長,m%長-1]&mdash;&mdash;>判斷是否越界
4:判斷兩個格子(一維數(shù)組編號)是否在一個集合(并查集查找)。如果在,則重新找,如果不在,那么把墻挖去
5:把墻挖去有點繁瑣,需要考慮奇偶判斷它那種墻(上下還是左右,還要考慮位置),然后擦掉。(根據(jù)數(shù)組轉(zhuǎn)換成真實距離)。具體為找一個節(jié)點,根據(jù)位置關(guān)系找到一維數(shù)組的號位用并查集判斷是否在一個集合中。
6:最終得到一個完整的迷宮。直到第一個(1,1)和(n,n)聯(lián)通停止。雖然采用隨機(jī)數(shù)找墻,但是效果并不是特別差。其中要搞清一維二維數(shù)組的關(guān)系。一維是真實數(shù)據(jù),并查集操作。二維是位置。要搞懂轉(zhuǎn)化!

注意:避免混淆,搞清數(shù)組的地址和邏輯矩陣位置。數(shù)組從0開始的,邏輯上你自己判斷。別搞混淆!


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲
主要邏輯為:

while(search(0)!=search(aa*aa-1))//主要思路
    {
        var num = parseInt(Math.random() * aa*aa );//產(chǎn)生一個小于196的隨機(jī)數(shù)
        var neihbour=getnei(num);
        if(search(num)==search(neihbour)){continue;}
        else//不在一個上
        {
           isling[num][neihbour]=1;isling[neihbour][num]=1;
            drawline(num,neihbour);//劃線
            union(num,neihbour);
         
        }
    }

那么在前面的代碼為

<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>	
  </head> 
  <body>
  <canvas id="mycanvas" width="600px" height="600px"></canvas>
    
  </body>
  <script type="text/javascript">
//自行添加上面代碼
    //      var mymap=new Array(36);
    //      for(var i=0;i<36;i++)
    //     {mymap[i]=-1;}
    function getnei(a)//獲得鄰居號  random
    {
        var x=parseInt(a/aa);//要精確成整數(shù)
        var y=a%aa;
        var mynei=new Array();//儲存鄰居
        if(x-1>=0){mynei.push((x-1)*aa+y);}//上節(jié)點
        if(x+1<14){mynei.push((x+1)*aa+y);}//下節(jié)點
        if(y+1<14){mynei.push(x*aa+y+1);}//有節(jié)點
        if(y-1>=0){mynei.push(x*aa+y-1);}//下節(jié)點
        var ran=parseInt(Math.random() * mynei.length );
        return mynei[ran];

    }
    function search(a)//找到根節(jié)點
    {
        if(tree[parseInt(a/aa)][a%aa]>0)//說明是子節(jié)點
        {
            return search(tree[parseInt(a/aa)][a%aa]);//不能壓縮路徑路徑壓縮
        }
        else
            return a;
    }
    function value(a)//找到樹的大小
    {
        if(tree[parseInt(a/aa)][a%aa]>0)//說明是子節(jié)點
        {
            return tree[parseInt(a/aa)][a%aa]=value(tree[parseInt(a/aa)][a%aa]);//不能路徑壓縮
        }
        else
            return -tree[parseInt(a/aa)][a%aa];
    }
    function union(a,b)//合并
    {
        var a1=search(a);//a根
        var b1=search(b);//b根
        if(a1==b1){}
        else
        {
            if(tree[parseInt(a1/aa)][a1%aa]<tree[parseInt(b1/aa)][b1%aa])//這個是負(fù)數(shù)(),為了簡單減少計算,不在調(diào)用value函數(shù)
            {
                tree[parseInt(a1/aa)][a1%aa]+=tree[parseInt(b1/aa)][b1%aa];//個數(shù)相加  注意是負(fù)數(shù)相加
                tree[parseInt(b1/aa)][b1%aa]=a1;       //b樹成為a樹的子樹,b的根b1直接指向a;
            }
            else
            {
                tree[parseInt(b1/aa)][b1%aa]+=tree[parseInt(a1/aa)][a1%aa];
                tree[parseInt(a1/aa)][a1%aa]=b1;//a所在樹成為b所在樹的子樹
            }
        }
    }

    function drawline(a,b)//劃線,要判斷是上下還是左右
    {

        var x1=parseInt(a/aa);
        var y1=a%aa;
        var x2=parseInt(b/aa);
        var y2=b%aa;        
        var x3=(x1+x2)/2;
        var y3=(y1+y2)/2;
        if(x1-x2==1||x1-x2==-1)//左右方向的點  需要上下劃線
        {
            //alert(x1);
            //  context.beginPath();
            context.strokeStyle = 'white';
            //    context.moveTo(30+x3*30,y3*30+15);//
            //   context.lineTo(30+x3*30,y3*30+45);
            context.clearRect(29+x3*30, y3*30+16,2,28);
            //    context.stroke();
        }
        else
        {
            //   context.beginPath();
            context.strokeStyle = 'white';
            //  context.moveTo(x3*30+15,30+y3*30);//
            //    context.lineTo(45+x3*30,30+y3*30);
            context.clearRect(x3*30+16, 29+y3*30,28,2);
            //      context.stroke();
        }
    }
     
    while(search(0)!=search(aa*aa-1))//主要思路
    {
        var num = parseInt(Math.random() * aa*aa );//產(chǎn)生一個小于196的隨機(jī)數(shù)
        var neihbour=getnei(num);
        if(search(num)==search(neihbour)){continue;}
        else//不在一個上
        {
           isling[num][neihbour]=1;isling[neihbour][num]=1;
            drawline(num,neihbour);//劃線
            union(num,neihbour);
         
        }
    }
  </script>
</html>

實現(xiàn)效果:


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲
如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲

方塊移動

這部分我采用的方法不是動態(tài)真的移動,而是一格一格的跳躍。也就是當(dāng)走到下一個格子將當(dāng)前格子的方塊擦掉,在移動的那個格子中再畫一個方塊。選擇方塊是因為方塊更方便擦除,可以根據(jù)像素大小精準(zhǔn)擦除。

另外,再移動中要注意不能穿墻、越界。那么怎么判斷呢?很好辦,我們再前面會判斷兩個格子是否聯(lián)通,如果不連通我們將把這個墻拆開。再拆的時候把這個墻的時候記錄這兩點拆墻可走即可(數(shù)組)

另外,事件的監(jiān)聽上下左右查一查就可以得到,添加按鈕對一些事件監(jiān)聽,這些不是最主要的。

為了豐富游戲可玩性,將方法封裝,可以設(shè)置關(guān)卡(只需改變迷宮大小)。這樣就可以實現(xiàn)通關(guān)了。另外,如果寫成動態(tài)存庫那就更好了。


如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲

以上是“如何使用數(shù)據(jù)結(jié)構(gòu)寫個Html5走迷宮游戲”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI