HarmonyOS純ets語言實現(xiàn)抓住神經(jīng)貓游戲
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??
1、前言
<<抓住神經(jīng)貓>>游戲相信不少朋友都玩過,最近不是ARKUI挺火熱的么,一直搞嵌入式的也想嘗嘗鮮,想找個小玩意入門,想起來5,6年前看過的一篇文章,分析神經(jīng)貓的尋路算法,號稱是最難抓住的神經(jīng)貓,回去一看,這項目不正好練手嗎,說干就干。
2、效果
目前已完成整個游戲的UI(當(dāng)然圖是網(wǎng)上找的),游戲邏輯(啟動,移動,勝負判定),可以學(xué)到的知識:ets方式的UI布局,ets組件化開發(fā)思想,自定義彈出框,ets語言構(gòu)造多叉樹,廣度優(yōu)先算法,最小路徑算法,設(shè)置圖片動畫等等,整體開發(fā)下來UI地方還算順暢,難到不難,只是這種聲明式UI和以前的命令式UI的編程方式需要一個思路轉(zhuǎn)變,最費時間的地方是那個貓跑路的算法,算法本來是薄弱項,這下正中軟肋了,不過好在翻了好幾本書,找了些資料,再看了點視頻,就搞定了,廢話少說,來個動圖感受一下。
先來個失敗的:
再來個成功的:
3、關(guān)鍵部分解讀
(1) 玩法
游戲的地圖是一個9*9交錯排列的一些灰色小圓點,初始情況下游戲生成地圖的時候會隨機選一些點變成橙色做為墻,然后玩家每次點擊一個灰色圓點,圓點變成橙色,同時貓移動一步,關(guān)于勝負的判定是貓被圈進一個圈子里面就為贏,當(dāng)貓跑到地圖邊邊上就為輸.玩法還是挺簡單的。
(2) 部分代碼
代碼結(jié)構(gòu)長這樣,因為時間關(guān)系,代碼的結(jié)構(gòu)還沒有優(yōu)化,有些地方看起來很是很混亂,包括文件名,變量名那些,后面有時間再調(diào)整吧,目前就將就看一下吧。
再貼個"貓"類吧:
@Observed
export class catData{
pos_x:number
pos_y:number
location:number
step:number = 0
inWall:boolean=false
constructor(loc:number = defaultLocation){
this.setLocation(loc)
}
reset(){
this.inWall = false
this.step = 0
this.setLocation(defaultLocation)
}
setLocation(loc:number){
console.log("set Loction:"+loc)
this.location=loc
this.setPosition()
}
setPosition(){
let col:number = Math.floor(this.location/9)
let row:number = this.location%9
this.pos_x = (col%2 ? row*38+17:row*38)
this.pos_y = col*38
// console.log("x:"+this.pos_x+" y:"+this.pos_y)
}
moveTo(location:number) {
this.setLocation(location)
this.step++
}
catInWall(yes:boolean=true){
this.inWall = yes
}
}
貓類的主要功能就是記錄移動步數(shù),然后移動位置,當(dāng)游戲重新開始的時候某些屬性復(fù)位。
(3) 主要邏輯
游戲的主要邏輯就是靠玩家點擊圓點發(fā)生,當(dāng)點擊圓點的時候,先將該點置為墻,然后先要找出貓能逃跑的路線,再讓貓選擇一條路線進行逃生,主要邏輯的代碼如下:
export function onItemClick(index : number){
console.log("onItemClick "+index)
if(myCircleDataArray[index].clicked ){
console.log("不能點擊")
return;
}
myCircleDataArray[index].setClick()
let catLocation = myCat.location
myCircleDataArray.forEach(item=>{
item.path = -100
item.depth = 100
})
myCircleDataArray[catLocation].depth=0
let neighbors = getNeighbors(catLocation,myCircleDataArray[catLocation].depth)
neighbors.forEach(item=> {
myCircleDataArray[item.location].depth=item.depth
})
let neighborList:Array<Neighbor> =neighbors
while(neighborList.length > 0){
let neighborsArrayList:Array<Neighbor> = []
neighborList.forEach(item=>{
let neighborsTemp = buildNeighborChild(item)
neighborsTemp.forEach(item=>{
neighborsArrayList.push(item)
})
})
neighborList = neighborsArrayList
}
neighbors.forEach(item=>{
calcCirclePath(item)
})
let best = getBestNeighbor(neighbors)
console.log("the best neighbor is:"+best.location+" path="+best.path);
if(best.path == 100){
console.log("cat is in wall");
myCat.catInWall()
myGame.setState(gameState.gameVictory)
}
myCat.moveTo(best.location)
if(catCheckLocation() == true){
console.log("cat escaped")
myGame.setState(gameState.gameFailed)
}
neighbors.length = 0
}
關(guān)于尋路算法這里說一下,目前采用的是廣度優(yōu)先遍歷,在找到幾條最短路徑,當(dāng)有兩條以上的最短路徑的時候,就看一下哪條路徑下的子路徑比較多(防止走入玩家設(shè)定的陷阱)。
function getBestNeighbor(neighbors:Neighbor[]):Neighbor{
let neighbor:Neighbor = neighbors[0]
//already get the shortest path
for(var i=1;i < neighbors.length;i++){
if(neighbor.path > neighbors[i].path){
neighbor = neighbors[i]
}
}
console.log("the shortest nei:"+neighbor.location)
//select the child more than other
for(var j=0;j < neighbors.length;j++){
if(neighbor.path == neighbors[j].path){
console.log("find same path:"+neighbors[j].location)
if(neighbor.child.length < neighbors[j].child.length){
neighbor = neighbors[j]
console.log("changed neighbor:"+neighbor.location)
}
}
}
return neighbor
}
開發(fā)的時候設(shè)置一個調(diào)試小技巧效率高很多(然而一開始的時候我也是個鐵憨憨,在草紙上記,弱爆了):
當(dāng)把這個置true的時候可以清晰的看到點的位置和到達邊界需要的步數(shù),神經(jīng)貓真是通過這個來跑路的,看一下打開的效果:
4、補充
(1) 后續(xù)
后續(xù)需要做的事情主要是以下幾件:
當(dāng)前可以看到3個難度圖標(biāo),目前還沒做功能,后續(xù)會加上,難度的調(diào)節(jié)目前認為有幾個地方:
初始墻的數(shù)量,逃跑算法的強度,或者優(yōu)化初始墻的位置(簡單的話就相對集中,困難的話就相對分散),以我非數(shù)學(xué)專業(yè)的功力感覺第一種靠譜一些,如果有數(shù)學(xué)大神也可以探討一下后面兩種怎么做。
可以看到貓?zhí)优艿臅r候,從當(dāng)前位置移動到下一位置,會出現(xiàn)短暫的消失,這有可能是模擬器在渲染動圖的時候有什么延時導(dǎo)致的,后期準(zhǔn)備研究一下動畫效果,讓貓的走動更順滑。
由于目前還沒有OpenHarmony能玩起來的開發(fā)板,所以只能是模擬器演示,后續(xù)如果有真正的開發(fā)板的話,相信很快看就能移植上去。
(2) 關(guān)于代碼
目前代碼托管在Gitee上,感興趣的小伙伴可以下載過來試一下,如果有什么建議或者改動也可以提提PR,提一下,這個游戲別看簡單,拿來入門練手還是非常合適的,如果一開始就搞什么復(fù)雜的界面或者交互很可能會打擊信心的哈。
代碼地址:https://gitee.com/yegren/CrazyCat。
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??