关于类DOTA游戏多样化技能系统的设计思考
在游戲里,每一個(gè)人物都有很多的技能。像DOTA,英雄聯(lián)盟一樣,技能也不都是單一的直線判斷,而是有很多的花樣。這類游戲的技能系統(tǒng)是如何設(shè)計(jì)的呢?
這里想從自動(dòng)機(jī)的角度來(lái)抽象這個(gè)問(wèn)題,以期得到一個(gè)更泛化的解決方案。因?yàn)槲沂且娉绦騿T而非game play,因此可能實(shí)際解決問(wèn)題未必和我的想法一樣。
首先,學(xué)習(xí)過(guò)自動(dòng)機(jī)理論或者是編譯原理,又或者對(duì)游戲人工智能方面有所了解的朋友一定聽(tīng)說(shuō)過(guò)自動(dòng)機(jī)的概念。這里我不怎么嚴(yán)謹(jǐn)?shù)拿枋鲆幌率裁词亲詣?dòng)機(jī):
(1)它擁有若干個(gè)狀態(tài)(State),其中有一個(gè)狀態(tài)是初始狀態(tài),并對(duì)應(yīng)若干結(jié)束狀態(tài);
(2)它擁有一個(gè)符號(hào)集,并接受符號(hào)集內(nèi)部的符號(hào)作為輸入;
(3)它擁有若干稱之為“狀態(tài)轉(zhuǎn)移函數(shù)”的邊,這些邊連接狀態(tài),把當(dāng)前狀態(tài)和輸入的符號(hào)作為參數(shù),并實(shí)現(xiàn)從一個(gè)狀態(tài)到另一個(gè)狀態(tài)的轉(zhuǎn)移。
這樣的自動(dòng)機(jī)一般是叫做有窮自動(dòng)機(jī),仔細(xì)看看,是不是和我們?cè)贚OL這類技能施放類的游戲的行為很類似?
試著把自動(dòng)機(jī)里的一些概念映射到游戲里:
(1)在LOL這類游戲里,的確存在很多顯式的狀態(tài)的概念,譬如說(shuō)死亡,減速,暈眩,這就是玩家當(dāng)前的狀態(tài)。
(2)用戶的輸入可以作為符號(hào)集,這里的用戶輸入有時(shí)候并不是按下了某個(gè)鍵這樣簡(jiǎn)單,而是更有意義的輸入:譬如某個(gè)技能是否已經(jīng)釋放到了一個(gè)人身上,又或者某個(gè)AOE技能是否與某個(gè)角色的包圍盒發(fā)生了碰撞。
(3)狀態(tài)轉(zhuǎn)移函數(shù)則是設(shè)計(jì)師定義的技能施放機(jī)制,譬如寒冰的劍射中敵人后對(duì)目標(biāo)產(chǎn)生暈眩效果,也就是使得敵方英雄從當(dāng)前狀態(tài)轉(zhuǎn)化到了暈眩狀態(tài)。
經(jīng)過(guò)這樣的抽象,整個(gè)英雄技能的施放就很有條理了:每個(gè)角色都有一個(gè)唯一的狀態(tài)機(jī),它的當(dāng)前狀態(tài)可以通過(guò)雙方玩家的輸入而發(fā)生轉(zhuǎn)移,轉(zhuǎn)移的規(guī)則作為一個(gè)個(gè)單獨(dú)的狀態(tài)轉(zhuǎn)移函數(shù)由策劃配表完成。
我們以LOL的幾個(gè)技能施放為例子,看看如何設(shè)計(jì)針對(duì)英雄自身的自動(dòng)機(jī)。
先看光輝女郎LUX的被動(dòng)技能的觸發(fā)機(jī)制:首先,敵方英雄當(dāng)前狀態(tài)是正常狀態(tài),接著LUX施放了一個(gè)傷害技能且該技能擊中了敵方英雄(也即是一個(gè)有效輸入),于是根據(jù)狀態(tài)轉(zhuǎn)移,這個(gè)技能使得敵方英雄掉血并且處于一個(gè)被標(biāo)記的狀態(tài),緊接著,LUX平A了敵方英雄一次,于是又有一個(gè)狀態(tài)轉(zhuǎn)移函數(shù),使得敵方英雄在被標(biāo)記的情況下掉了額外的生命值,同時(shí)使得該英雄重新回到了正常狀態(tài)。這是一個(gè)非常典型的一次技能判斷機(jī)制。
但這里就存在一個(gè)問(wèn)題,有朋友就會(huì)說(shuō),這樣簡(jiǎn)單的輸入->反饋式的邏輯誰(shuí)不會(huì)寫啊,引入所謂的自動(dòng)機(jī)有什么用?真實(shí)的MOBA類游戲里,很多技能的施放和產(chǎn)生的效果并不是僅僅由用戶的一個(gè)輸入行為決定,甚至不是一個(gè)狀態(tài)決定,一個(gè)結(jié)果或者一個(gè)狀態(tài)轉(zhuǎn)移很可能是由多個(gè)角色身上的已知狀態(tài)以及多個(gè)用戶的同時(shí)輸入來(lái)決定的,如何引入多輸入或者多狀態(tài)的狀態(tài)轉(zhuǎn)移函數(shù)呢?
我們?cè)僖胍活惛鼮閺?fù)雜的自動(dòng)機(jī),這類自動(dòng)機(jī)叫做下推自動(dòng)機(jī)。下推自動(dòng)機(jī)和有窮自動(dòng)機(jī)幾乎一樣,唯一的不同是,下推自動(dòng)機(jī)除了狀態(tài),輸入,和狀態(tài)轉(zhuǎn)移函數(shù)以外,還包含一個(gè)可操作的數(shù)據(jù)棧。這個(gè)數(shù)據(jù)棧的操作可由狀態(tài)轉(zhuǎn)移函數(shù)來(lái)進(jìn)行操作,狀態(tài)轉(zhuǎn)移函數(shù)可以把用戶之前的輸入壓入棧里或者從棧里取出來(lái)使用。這樣,用戶先前的一些狀態(tài)就能夠被記錄下來(lái)而不用使用組合來(lái)生成新的狀態(tài)。
比如有一個(gè)技能,當(dāng)施放時(shí),如果敵方,同時(shí)處于暈眩+減速+血量低于百分之五十,就對(duì)敵人造成一擊必殺(死亡狀態(tài)),如果是先前的有窮自動(dòng)機(jī),我們要表示這樣一個(gè)狀態(tài),可能需要重新定義一個(gè)新的狀態(tài):X英雄一擊必殺的狀態(tài)(也就是暈眩+減速+血量低于百分之五十),一旦隨著游戲邏輯的復(fù)雜,這樣的狀態(tài)將會(huì)呈幾何級(jí)數(shù)增加。反過(guò)來(lái),如果是使用下推自動(dòng)機(jī),我們則不需要定義新的狀態(tài),只要有暈眩,減速和血量低于百分之五十這三個(gè)單獨(dú)的狀態(tài),然后當(dāng)暈眩發(fā)生時(shí),狀態(tài)轉(zhuǎn)移函數(shù)從正常狀態(tài)轉(zhuǎn)移到暈眩,同時(shí)把暈眩狀態(tài)作為一個(gè)輸入壓入到數(shù)據(jù)棧里,緊接著,又發(fā)生了減速,那么從暈眩轉(zhuǎn)移到減速,再把減速壓入到數(shù)據(jù)棧里,此時(shí)血量低于百分之五十的話,可以再讓用戶進(jìn)入血量低于百分之五十的狀態(tài)。當(dāng)處于這一狀態(tài)時(shí),再接受X英雄放了大招,這時(shí)候狀態(tài)轉(zhuǎn)移函數(shù)以X的大招作為輸入,當(dāng)前處于血量低于百分之五十的狀態(tài),同時(shí)從當(dāng)前數(shù)據(jù)棧里找到了另外兩個(gè)必要條件:暈眩和減速,那么以此為依據(jù),讓敵方英雄進(jìn)入死亡狀態(tài)。
同時(shí),我們的狀態(tài)轉(zhuǎn)移附加的事(比如施加暈眩狀態(tài),手機(jī)游戲或者使其進(jìn)入血量低于百分之五十),這可以抽象成一系列的原子行為被附著在狀態(tài)轉(zhuǎn)移函數(shù)中,而狀態(tài)轉(zhuǎn)移函數(shù)則負(fù)責(zé)依次觸發(fā)這類行為,而有些行為我們可以認(rèn)為是同步的,有些則是異步的。譬如三秒的暈??梢岳斫鉃橐粋€(gè)異步操作,它分兩個(gè)階段執(zhí)行,第一階段是開(kāi)始時(shí)施加暈眩,第二階段是結(jié)束時(shí)取消暈眩,這類異步操作就進(jìn)一步化為了兩個(gè)原子操作。狀態(tài)轉(zhuǎn)移函數(shù)的目的就變成了調(diào)度一系列行為的觸發(fā),同時(shí)轉(zhuǎn)換(Switch)當(dāng)前的狀態(tài)。
所以到目前為止,我們抽象出的結(jié)構(gòu)有這么幾個(gè):狀態(tài),行為,輸入,狀態(tài)轉(zhuǎn)移函數(shù)(一系列的行為調(diào)度+一個(gè)狀態(tài)的切換),它的拓?fù)浣Y(jié)構(gòu)和圖的類型非常接近,因此可以讓策劃用配表的形式把這種圖的給表示出來(lái)并簡(jiǎn)單的存儲(chǔ)在一個(gè)XML文件里。程序要做的事情則是通過(guò)策劃配表得到的XML文件重建這個(gè)設(shè)計(jì)好的自動(dòng)機(jī),并把相應(yīng)輸入link到這個(gè)自動(dòng)機(jī)的輸入端,同時(shí)把行為綁定為一些固化的執(zhí)行函數(shù)。
這是一個(gè)比較基礎(chǔ)的玩法,如果想要玩的更復(fù)雜,也有一些腦洞可以開(kāi),比如說(shuō),程序員都聽(tīng)說(shuō)過(guò)正則表達(dá)式,以及可能不一定聽(tīng)說(shuō)過(guò)的上下文無(wú)關(guān)文法,這類表示方法能夠非常簡(jiǎn)潔有效地表示一個(gè)技能的觸發(fā)規(guī)則,如果你的策劃能夠了解和熟悉這樣優(yōu)雅的規(guī)則表示法,并且能夠把他想要設(shè)計(jì)的技能或者英雄用一個(gè)上下文無(wú)關(guān)文法或者正則表達(dá)式來(lái)表示出來(lái),同時(shí)你又有足夠的能力設(shè)計(jì)出這樣的語(yǔ)法解析器,那么你完全可以把一個(gè)技能施放系統(tǒng)當(dāng)做一個(gè)編譯器的前端解析器來(lái)實(shí)現(xiàn)。同時(shí)引入一些邏輯操作符來(lái)豐富規(guī)則,譬如與(AND)或(OR),或者閉包操作等。
除過(guò)這里介紹的自動(dòng)機(jī),實(shí)現(xiàn)類似行為的另一個(gè)常用結(jié)構(gòu)是所謂行為樹(shù)(Behavior Tree),但從我的理解來(lái)看,這和編譯原理中講到的語(yǔ)法樹(shù)沒(méi)有太多不同。
所以其實(shí)現(xiàn)在很多游戲中需要考慮和解決的問(wèn)題,在經(jīng)典的算法和基礎(chǔ)計(jì)算機(jī)理論層面已經(jīng)有很多聰明的先驅(qū)提出了很多優(yōu)雅的算法,往往通過(guò)合理的抽象我們都能把游戲中的問(wèn)題規(guī)約為這類經(jīng)典問(wèn)題來(lái)解決,而很多國(guó)內(nèi)的game play程序員喜歡發(fā)明些trick來(lái)臨時(shí)解決,最后的結(jié)果往往就是補(bǔ)丁打補(bǔ)丁,代碼可讀性極差,還是因?yàn)楹雎曰A(chǔ)理論和基本功不扎實(shí)。
總結(jié)
以上是生活随笔為你收集整理的关于类DOTA游戏多样化技能系统的设计思考的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 游戏中常用的寻路算法(5)预先计算好的路
- 下一篇: 使用行动列表去创造简单且可扩展的游戏AI