首頁 >web前端 >js教程 >純HTML5製作圍住神經貓遊戲-附源碼下載_javascript技巧

純HTML5製作圍住神經貓遊戲-附源碼下載_javascript技巧

WBOY
WBOY原創
2016-05-16 15:43:302493瀏覽

HTML5圍住神經貓遊戲網頁版是基於HTML5、jquery、Typescript等技術製作的圍住神經貓遊戲。

先附上示範和原始碼下載,點選這裡  看示範     下載來源碼

去年風靡微信朋友圈的小遊戲“圍住神經貓”,我也試著做了一下。遊戲是用Egret引擎開發的,因為Egret是用Typescript語言建構的,因此這裡遊戲也是用Typescript來開發的。

遊戲規則:

點擊畫面上的灰色格子,慢慢將神經貓圍起來抓住。如果貓咪到達遊戲區邊緣則遊戲失敗。

準備素材

在網路上搜尋「圍住神經貓」遊戲,打開一個,並打開偵錯介面,從network或resource中把貓、灰色圓圈、橘色圓圈等圖片扒下來保存到本地。

要注意的是,Egret新的MovieCilp架構設計以及MovieClip資料格式標準都與早期有些不同,我從網上扒下來的已經不適用了,根據新的數據格式標準做修改後mc的json文件如下:

{"mc":{
 "stay":{
 "frameRate":20,
 "labels":[],
 "frames":[
   {"res":"stay0000","x":0,"y":0},
   {"res":"stay0001","x":0,"y":0},
   {"res":"stay0002","x":0,"y":0},
   {"res":"stay0003","x":0,"y":0},
   {"res":"stay0004","x":0,"y":0},
   {"res":"stay0005","x":0,"y":0},
   {"res":"stay0006","x":0,"y":0},
   {"res":"stay0007","x":0,"y":0},
   {"res":"stay0008","x":0,"y":0},
   {"res":"stay0009","x":0,"y":0},
   {"res":"stay0010","x":0,"y":0},
   {"res":"stay0011","x":0,"y":0},
   {"res":"stay0012","x":0,"y":0},
   {"res":"stay0013","x":0,"y":0},
   {"res":"stay0014","x":0,"y":0},
   {"res":"stay0015","x":0,"y":0}
 ]
 }},
 "res":{
  "stay0000": {"x":0,"y":0,"w":61,"h":93},
  "stay0001": {"x":61,"y":0,"w":61,"h":93},
  "stay0002": {"x":122,"y":0,"w":61,"h":93},
  "stay0003": {"x":183,"y":0,"w":61,"h":93},
  "stay0004": {"x":0,"y":93,"w":61,"h":93},
  "stay0005": {"x":61,"y":93,"w":61,"h":93},
  "stay0006": {"x":122,"y":93,"w":61,"h":93},
  "stay0007": {"x":183,"y":93,"w":61,"h":93},
  "stay0008": {"x":0,"y":186,"w":61,"h":93},
  "stay0009": {"x":61,"y":186,"w":61,"h":93},
  "stay0010": {"x":122,"y":186,"w":61,"h":93},
  "stay0011": {"x":183,"y":186,"w":61,"h":93},
  "stay0012": {"x":0,"y":279,"w":61,"h":93},
  "stay0013": {"x":61,"y":279,"w":61,"h":93},
  "stay0014": {"x":122,"y":279,"w":61,"h":93},
  "stay0015": {"x":183,"y":279,"w":61,"h":93}
 }}

寫程式

主要總結下我在開發過程中遇到的主要的兩個難題。

問題一,貓咪該如何逃跑?

在這個遊戲中,每個圓圈可能有三種狀態

可通行,灰色圓圈表示

有路障,不可行,橘色圓圈表示

被貓佔領,灰色圓圈,貓的動畫疊置於其上

每當點擊了灰色圓圈,就會將其變成橙色圓圈即路障狀態,同時貓咪會緊跟著點擊的動作也向周邊走一步。

行走方向

遊戲區由9*9個圓圈組成,偶數行縮排圓圈半徑大小的寬度,這樣的佈局導致,貓理論上可以有6個行走方向(每次只能走一步),分別是左,左上,右上,右,右下,左下,如這些位置上的圓圈為路障狀態,則相應方向不可通行。

如果這六個方向的鄰居有五個都為路障,那當然很好選擇線路,剩下的那個就是唯一的出路了,但是顯然情況不可能如此簡單。我們遇到的更多的情況是,六個方向的鄰居上,有直接為路障狀態的(那自然絕對不走這一步),有是可通行狀態的,但是彼此向邊緣的可及性不同。

 

如上圖中,目前,貓咪的左方向走三步即可到達邊緣,右上、右下向走四步可達,左上、右方向上可走一步但即遇路障,左下方向走三步遇路障。這時候我們當然應該要為這六個方向的優先順序。

優先權

我是這樣設定優先順序的:

一路通行的方向>會出現路障的方向,如此圖中左、右上、右下>左上、右、左下

一路通行的方向中,離邊緣越近優先權越高,如此圖中左>右上、右下

會出現路障的方向中,可走的步數越多優先級越高,如此圖中左下>右、左上

以下將這些約定的可及性用數值來體現以便比較,設這個值為accessibility,數值越大優先順序越高。

一路通行的方向

accessibility = 1/stepToEdge; //stepToEdge表示離邊緣還有幾步

會出現路障的方向

accessibility = (-1)/stepToBlock;//stepToBlock表示離路障的距離

接下來考慮分母如果為0怎麼辦,在第一種情況中,分母為0,表示貓目前已經在邊緣了,那麼也不用判斷優先級了,遊戲已經失敗了。第二種情況中,分母為0表示出門即遇路障,這個方向不用考慮了是絕對走不通的,那麼它的優先權就定為-1。

這樣一輪算下來,六個方向上的accessibility值分別為:

左:1/3

左上:-1

右上:1/4

右:-1

右下:1/4

左下:-1/3

這樣比較下來優先權應該是左>右上>右下>左下>左上>右。

為什麼左上與右,右上與右下,這兩組內部的值明明一樣,我們依然是排出了順序呢?只是因為我們計算是從左邊方向開始順時針旋轉的。如果數值一樣,那就看出現的順序了。

所以在上圖這種情況下,貓會向左走一步。

問題二,如何判斷貓咪被圍住了?

在網路上玩這個遊戲的時候,我發現當貓被圍住的時候會換成一種「被圍住」的動作,那麼該如何判斷貓被圍住了,然後改變它的動作動畫?

「被圍住」與「被抓住」不一樣,它早於「被抓住」的狀態。當貓無路可走的時候,它就「被抓住」了,遊戲獲勝。而「被圍住」指的是貓暫時還有路可走,但是已經被包圍住了,垂死掙扎而已,如下圖。

 

我的思路是這樣的:

從貓咪目前的位置找六個方向中可通行的鄰居,然後從這些鄰居出發,再找它們各自的可通行鄰居,一直這樣找下去,一邊找的過程中,一邊判斷當前已經找到的鄰居中有沒有處在遊戲區邊緣的,如果有,那麼尋找過程提前結束,判斷結果是:貓沒有被圍住。如果直到所有的可通行鄰居都找到了,裡面都沒有處在遊戲區邊緣的,那麼判斷結果是:貓被圍住了。
接下來用程式碼實作這個判斷過程。

首先,需要准备一个方法,判断圆圈是否已经处在圆圈边缘了,假设这个方法名及参数如下,内部实现比较简单这里就不贴了。

/*
判断传入的circle是否在边界上
 */
private isCircleAtEdge(circle:Circle):boolean {
 ...
}

再准备一个方法,获取某圆圈周围某方向的邻居。

private getCircleNeighbor(circle:Circle,direction:Direction):Circle{
  ...
}

最后,是判断的核心方法。

/*
能否在circle位置出发找到路线到达边缘
*/
private canExitAt(circle:Circle):boolean{
 var ignoreArr=[];//不用再处理的circle集合
 var toDealWithArr=[circle];//还需进行判断的circle集合
 while(true){
  if(toDealWithArr.length<1){
   return false;
  }else{
   var _first=toDealWithArr.shift();
   ignoreArr.push(_first);
   if(_first.getStatus()!==CircleStatus.Blocked&&this.isCircleAtEdge(_first)){
    return true;
   }else{
    for(var i=Direction.LEFT;i<=Direction.BOTTOM_LEFT;i++){
     var nbr=this.getCircleNeighbor(_first,i);
     if(!(ignoreArr.indexOf(nbr)>-1||toDealWithArr.indexOf(nbr)>-1))
     if(nbr.getStatus()!==CircleStatus.Available){
      ignoreArr.push(nbr);
     }else{
      toDealWithArr.push(nbr);
     }
    }
   }
  }
 }
}

在方法体的最开始,准备好两个数组,一个用来存储不用再处理的圆圈集合ignoreArr,另一个用来存储还需要进行判断的圆圈集合toDealWithArr。每找到一个可通行的邻居,首先要判断它是不是第一次出现(因为几个圆圈可能会有共同的邻居,所以一个圆圈可能因为它是多个圆圈的邻居而被找到多次),判断的标准就是它有没有出现在ignoreArr或toDealWithArr里,如果没有那么就是第一次出现,如果它是路障,那么塞到ignoreArr,如果不是路障,那么推入toDealWithArr尾部等待判断。

每次循环开始时,我们会从toDealWithArr头部弹出一个圆圈对象,对它是否在边缘做判断,如果是,那么返回true跳出循环,猫没有被围住,它可以通过某条路线到达边缘。如果toDealWithArr全部判断完了都不在边缘,那么返回false,猫被围住了,它的直接邻居及众多间接邻居中没有一个是在边缘的。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn