寫一個狼吃羊的小遊戲

junior發表於2019-06-16

其實在2016年,我就準備寫這個小遊戲了。但是奈何當時沒文化?,也還沒有轉行成前端。既沒有物件導向的思想,也不懂什麼尋徑演算法,更不瞭解模組化,只是掌握了canvas的基本知識。所以以當時的水平,就搞了一段時間後,把羊,狼,磚塊畫了出來,具體怎麼運動?搞不下去,就擱置下來了。時間飛逝,這個小遊戲就這麼靜靜地爛尾了兩年多,直到前幾天,在codepen上看到了一個尋徑的demo,才又重新撿起來。

現在再撿起來,感覺得心應手應手了許多,儘管中間也碰到了一些坑,但不至於無從下手。儘管還有許多可以改進的地方,程式碼寫的也不怎麼規範,斷斷續續搞了一週多,好歹搞出來一個能用的版本。下面說說開發過程中遇到的一些問題,和學到的知識。

這裡是試玩地址:https://www.imgss.top/demo/wAs/
github: https://github.com/imgss/wAs

寫一個狼吃羊的小遊戲

一 devicePixelRatio

在手機上開啟這個小遊戲時,遊戲畫面會變得比較模糊,這是由於手機螢幕的css尺寸和真實的物理畫素數量是不一樣的。這也是window.devicePixelRatio這個屬性存在的意義。同時canvas的css寬度和canvas本身的寬度也是這個區別。舉個例子:

一個手機的 devicePixelRatio 是3,canvas的css寬度是500px,要想使canvas繪製出的圖片不模糊,需要給canvas的寬度設定成多少?答案是500 * 3 = 1500。寫成程式碼是:

    var ratio = window.devicePixelRatio;

    var oldWidth = canvas.width;
    var oldHeight = canvas.height;
    
    canvas.width = oldWidth * ratio; //根據radio設定新的width,解決圖片模糊問題
    canvas.height = oldHeight * ratio;
    canvas.style.width = oldWidth + "px";
    canvas.style.height = oldHeight + "px";//使canvas在螢幕上的顯示和之前保持一致

二 尋徑演算法

這也是整個遊戲最難的地方,遊戲中羊是在不斷運動的,狼需要根據羊當前的位置計算出行動路徑。在實現中,我參考了codepen上的這個demo,具體的思路是,用一個二維陣列來表示整張地圖,從目標節點(羊的位置)開始,向上下左右遍歷,如果碰到牆或者邊界就停止,並標記為訪問過。再根據這些節點的兄弟節點進行遍歷,直到找到狼所在的位置,或者整個地圖全部搜尋了一遍。

當在遍歷中找到狼的位置後,進行一次回溯,就拿到了狼的運動路徑。

整個演算法在search.js中,是根據上面的那個demo修改的,實現了一個pathFinder類;

export default class Pathfinder{
  constructor(gridData, targetPosition, foundCallback) {
    this.gridData = gridData;
    this.targetPosition = targetPosition;

    this.foundCallback = foundCallback;
    this.width = this.gridData[0].length;
    this.height = this.gridData.length;
  }
  // 將二維地圖轉換成節點資料
  parseGridData() {
   ...
  }

瞭解更多的尋徑演算法知識可以看這篇文章: https://www.redblobgames.com/pathfinding/a-star/introduction.html

三 一個有用的庫

在開發過程中發現手機端的操作不是很流暢,找到了一個叫nipplejs的虛擬搖桿的庫。使用方法也很簡單,虛擬搖桿可以是固定在螢幕的某個地方,也可以是顯示在螢幕的任何一個地方。但是在實際中使用發現,用搖桿操作,很容易導致羊多跑或者少跑一兩格,對於這個遊戲來說,不如箭頭控制精度好,最終還是放棄了。

遊戲裡還用到一個sweetalert庫,用來做彈出框的,沒有依賴,用起來很方便(其實是做不出酷炫的彈窗特效)。

後記

整個過程中,加深了自己對演算法重要性的認識,雖然前端很少涉及高深的演算法,但是多懂一點演算法知識絕對大有裨益。小遊戲中還有許多值得優化的地方,也還有幾個bug,這些以後再慢慢優化吧。(完)

相關文章