其實在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,這些以后再慢慢優化吧。(完)