從多角度看易擴展的游戲技能系統(tǒng)設(shè)計
一個好擴展的技能系統(tǒng)能讓技能、BUFF、道具之間的關(guān)系能夠很好的表示和調(diào)整,對游戲開發(fā)而言無疑是減少了不少的加班時間。那么要怎么設(shè)計一個易擴展的游戲技能系統(tǒng)呢?游資網(wǎng)從游戲策劃、程序和玩家這三個角度進行整理:
策劃角度:
作者:猴與花果山
感覺這個問題很久不提了但是還是值得拿出來探討下。我花了至少5年在設(shè)計和實踐(我自己經(jīng)歷了大小7個項目,雖然大多最后因為其他原因都沒上)這樣一套機制并且可以說基本解決了這個問題!我并不想藏著他,我也和很多朋友分享了,同時也感謝他們提出了很多意見,包括細節(jié)和優(yōu)化等方面,正因為互相之間的借鑒和交流,我到今天已經(jīng)把這套機制歸納的非常好了,還是想把它分享給更多想做好游戲的人,希望大家能進一步交流,把它更完善化,以形成一種規(guī)范,這套機制適用于任何類型的游戲開發(fā),因為他是一個很棒的思路。
首先分析一下可擴展性:我從一個設(shè)計師的角度來看,所謂的可擴展性是——你并不知道策劃下一個設(shè)計的是什么,但是你需要在盡可能不改動核心代碼的基礎(chǔ)上去把它實現(xiàn)了,并且在調(diào)試的時候(甚至是上線之后要做調(diào)整的時候),你可以并不傷筋動骨的去修改它。這里除了你要有好的代碼規(guī)范外,還需要抽象一套機制來實現(xiàn)它。
實際上,好的策劃的腦洞是非常大的,你真不知道他會設(shè)計出什么樣的技能,但你并不能說一些設(shè)計因為無法實現(xiàn)就理所應(yīng)當被埋沒了,(我對策劃設(shè)計Dota類游戲的思路要求是開放的,發(fā)揮想象力的,
因此我想了這樣一個機制:[設(shè)計思想] 游戲系統(tǒng)設(shè)計思路的牢籠 一味追求實用性
他們的核心在于:
- 明確區(qū)別了AOE\Buff和技能3塊,策劃應(yīng)該從這個角度出發(fā)思考問題。
- 這既然是一套機制,你可以把它用在任何游戲的框架當中。比如我要做一個Dota傳奇的卡牌游戲,一樣可以用這套機制,但是核心在于——你的策劃要有能力歸納出游戲中的回調(diào)點。
當然我們在使用這套機制的時候,邏輯上實現(xiàn)并沒有任何問題,但是我們一樣會遇到一些從邏輯變成動畫的困難,尤其是當我們的戰(zhàn)斗在服務(wù)器上一瞬間完成了,但是要把結(jié)果告訴客戶端嗎,并且有客戶端重新驗算一遍的時候,因此我在之后有總結(jié)了一套作法,來完成這個事情:手游回合制游戲戰(zhàn)斗機制歸納式設(shè)計
這個解決的是,當你有各種有趣的buff,但是又想不大改客戶端的時候,你應(yīng)該這樣去建立這個框架。你可以想象如果你做一個MT類型的游戲,戰(zhàn)斗是服務(wù)器一瞬間的,但你又要客戶端重演,我們舉個例子:
比如我門設(shè)計了在MT類型游戲中加入地形因素:可以有火海,火海每回合開始的時候?qū)λ袌錾蠑澄矣⑿墼斐苫鹧鎮(zhèn)Α?/p>
然后有個英雄是一只鳳凰,鳳凰有2個被動效果:
- 受到火焰?zhèn)Φ臅r候變成治療自己相當于傷害值的血量。
- 戰(zhàn)斗中第一次死亡可以復(fù)活,回復(fù)最大生命值50%,如果在火海中則回復(fù)100%。
這樣一個英雄和地形,我們?nèi)绾螌崿F(xiàn)呢?如果你看了我上面的幾套機制,并且理解了,那基本沒有難度,你根本不需要硬編碼。但這里有個問題,我如何讓客戶端重現(xiàn)?這就是上面這篇說的關(guān)鍵了。
程序角度:
作者:扼殺黑暗
技能沒什么框架,只是有很多字段罷了。
比如 cd 施法距離、釋放動畫、飛行動畫等等。。。
其實游戲技能不是一直不是什么難點,畢竟根據(jù)每個屬性實現(xiàn)邏輯就好了。
技能真正麻煩一點是其實是 所謂的“效果”。
因為從很久以前,游戲設(shè)計的時候就把效果這個概念添加進來了。
對于 游戲戰(zhàn)斗對象主體,我們暫時叫做BattleAgent簡稱BA。
影響B(tài)A的數(shù)據(jù)有很多,比如移動速度 攻擊力 基礎(chǔ)屬性 等等,影響的入口也有很多:
技能
buff/被動技能
裝備
強化
寶石
魂
等等,而這些實際上從影響結(jié)果沒什么區(qū)別。
首先我們先談區(qū)別,對于這些數(shù)值影響,其實區(qū)別只有入口或者說是作用的方式,
技能是BA(castor)對BA(target)釋放造成的瞬間數(shù)值影響。
buff是castor對BA(target)安裝后造成的持續(xù)數(shù)值影響,分為按時觸發(fā)瞬發(fā)和持續(xù)修改數(shù)值。
裝備是特定容器對BA持續(xù)修改數(shù)值。
所以這里游戲開發(fā)者們抽象出了 效果這個概念。
對與效果而言,只存在2個行為:
- 對BA產(chǎn)生數(shù)值影響
- 對BA撤銷數(shù)值影響
所以效果最終定義為:
- interface Effect {
- void cast(BattleAgent target);
- default void reverse(){
- }
- }
而對于其他功能實體來說,就可以簡化為效果的容器:
- interface EffectContainer extends Effect{
- List<Effect> getEffects();
- }
這樣我們就只要定義不同效果容器就可以了,
比如技能:
- class abstract Skill implements EffectContainer{
- public void spellTo(BattleAgent target){
- foreach(Effect effect in getEffects()){
- effect.cast(target);
- }
- }
- }
對于buff:
- class abstract Buff implements EffectContainer{
- public void update(){
- foreach(Effect effect in getEffects()){
- effect.cast(target);
- }
- }
- }
對于被動技能(其實也是buff):
- class abstract BuffSkill extends Buff {
- public void install(){
- foreach(Effect effect in getEffects()){
- effect.cast(target);
- }
- }
- public void unstall(){
- foreach(Effect effect in getEffects()){
- effect.reverse(target);
- }
- }
- }
裝備同理被動技能,
是不是很清晰?
而對于復(fù)雜的技能效果,因為我們已經(jīng)抽象出了Effect。
所以怎么實現(xiàn)也就很容易了!
- class DamageEffect implements Effect{
- private int damage = 100;
- public void cast(BattleAgent target){
- target.hp -= damage;
- }
- }
看起來是不是很簡單,我們來寫個變羊。
這個技能包括 2 個效果 外形修改和屬性。
1 外形變羊
- class ChangSheepEffect implements Effect{
- public void cast(BattleAgent target){
- target.gameObject = GameManager.getAnimeObject("sheep");
- }
- }
2 攻擊力和防御力變0 速度變慢
- class PropChangeEffect implements Effect{
- public void cast(BattleAgent target){
- target.atk = 0;
- target.def = 0;
- target.speed = 50;
- }
- }
就是這么簡單,同學(xué)你明白了嗎?
如果要深入一點的話,就是變羊是持續(xù)型的,到了時間會變回來。
所以我們要一個可以觸發(fā)buff的效果:
- class TriggerBuffEffect implements Effect{
- BuffSkill buff = new BuffSkill (){
- public List<>getEffects(){
- return new List().add(new ChangSheepEffect()).add(new PropChangeEffect());
- }
- }
- public void cast(BattleAgent target){
- int time = 3000;//3秒
- target.addBuff(buff,time);
- }
- }
然后把這個TriggerBuffEffect加到技能能上就ok了,就完成了一個可以變羊3秒的技能。
玩家角度:
作者:梧桐
這篇文章想表達的是我作為一個玩家,不是作為商業(yè)公司的員工,所謂的程序、美術(shù)或策劃,對感興趣的一些游戲技能體系的一些分析。
這個要看追求了,沒追求一張 excel 表配置上幾百個參數(shù),碰到一個需求加一個總能寫出來;有追求甚至能和 war3 一樣十幾年前的游戲就可以在沒有源碼情況下做出 dota(然而總有嘴強王者認為這沒有什么大不了);又或者像我一樣幻想有沒有可能設(shè)計出一套集成 GTA(模擬現(xiàn)實)+神之浩劫(moba)+虐殺原型(超現(xiàn)實動作)又可供玩家擴展的技能系統(tǒng)?
技能是如此有意思的事情,精巧的、可擴展的技能框架簡直可以說是游戲最大的樂趣,遠不是一些泡菜網(wǎng)游里面一句一切皆 buff 就能把我打發(fā)了的,所以很久以來我對探索技能在各種游戲里面的實現(xiàn)樂此不疲,分享一點研究的線索。
比較少談具體的編碼細節(jié),因為就像我本篇最后說的那樣,研究多了甚至開始反思技能這樣一個概念到底存不存在,或者說不同游戲類型討論的技能真的是同一種東西嗎?如果游戲真的是現(xiàn)實生活的映射,那我們?nèi)祟愖鳛榻巧珦碛屑寄軉幔?/p>
最簡單的就是虛幻競技場那種 fps,感覺這種沒什么好說的,雖然虛幻競技場的改裝槍是一個玩點,但是代碼層面并不復(fù)雜。
復(fù)雜點的泡菜網(wǎng)游 rpg 或者 moba 可以參考星際爭霸的銀河編輯器,風暴英雄就是用這個做出來的。
熟悉 war3 不熟悉 sc 就下載 ga 的 war3 mod(魔獸爭霸III 2015),這是論壇頭目在 sc 體系下完整的復(fù)刻了 war3,可以觀察 war3 里面的技能一個一個是怎么實現(xiàn)的,常見的比如暴風雪、空中鎖鏈、變羊、風暴之錘等等,其實簡單的的網(wǎng)游技能無非就是這些技能的變種。
里面大體來說把技能相關(guān)的東西解耦成了如下模塊,unit、action、order、ability、behavior、effect、actor,然后通過反射和連線配置來擴展游戲。
簡單描述這個體系,很復(fù)雜,也不求沒研究過的人能看懂:ability 就是通俗意義上的技能,包裝成 order 被 unit 調(diào)用,ability 本身不負責技能邏輯,只有使用 ability 消耗的資源(比如消耗多少魔法)前搖后搖之類的處理,他指向一個 effect,在 ability 調(diào)用時候轉(zhuǎn)發(fā)到 effect 身上;effect 晚點說,先說 behavior,常見的 behavior 類型就是添加一個 buff,也就是對一個屬性的階段性修改,behavior 是有狀態(tài)的;回頭說 effect,effect 最終組成了一顆 effect 樹,effect 常見的有發(fā)射投射物、應(yīng)用 behavior、周期性的調(diào)用下一個 effect、對區(qū)域進行搜索然后對搜索到的每個對象進行調(diào)用 effect、造成傷害、創(chuàng)建單位等,除了周期性效果之外的 effect 都是無狀態(tài)的,只是簡單的對邏輯進行一次函數(shù)調(diào)用。以上所有的一切描述都是純邏輯層面的,而 actor 是表現(xiàn)體,所有的特效、動畫都是通過 actor 監(jiān)聽以上所有對象的信號 來做出相應(yīng)的反應(yīng),而不是常見的動畫驅(qū)動邏輯,換句話說,如果 actor 不監(jiān)聽邏輯層的信號,表現(xiàn)會有問題,但是游戲的核心邏輯還是照樣跑,包括 unit 類其實都不包括任何的表現(xiàn)信息,只是在 unit 類創(chuàng)建時候通知 actor 創(chuàng)建并做表現(xiàn) 。actor 很類似一個完全被動驅(qū)使的客戶端,其他模塊是服務(wù)器。最后,在整個一套異步流程中,需要一些全局的類似 ai 中的黑板數(shù)據(jù),記錄比如施法者、施法位置、目標攻擊位置、目標攻擊對象等,由于 effect behavior 的樹狀向下擴散,所以這個黑板數(shù)據(jù)其實也要不停地更換上下文,這個就有點復(fù)雜了。
另外,表現(xiàn)層的 actor 的技能動作處理,也比較有意思,采用動作名稱模糊匹配的思路:大概就是這樣的:對角色當前各種狀態(tài)進行采樣(比如心情、天氣、角色上一個狀態(tài)名稱等),根據(jù)狀態(tài)類型優(yōu)先級自動選擇最合適的且存在的動作,比如如果資源同時存在Attack 00 Attack 01動作,那就隨機播放一個 Attack,再比如風暴英雄里面普通死亡、爆炸死亡、天空擊飛死亡播放不同動作也是在這個層次處理的。當然,動作模塊的設(shè)計是個大問題,各大引擎中間件也經(jīng)常是一個版本一個方案的大改,他這套方案也有局限性。好處就是用起來方便,ruby 曰:約定大于配置。想象一下,當玩家新做一個路人角色,這個角色在看到美女時候就自動做特定的好玩動作,而這一切需要做的也許僅僅是,配置一個 npc,給他一個特定名稱的動作,比如 love stand。星際目前有296個關(guān)鍵字可以相互組合。
再談一個小細節(jié),一般自研引擎都解決的比較好,但是也可能還有人還沒注意這件事:星際美術(shù)的動作資產(chǎn)中,除了骨骼動畫,聲音、特效等實時演算的功能也集成在里面,而且編輯器可以做到直接預(yù)覽,上層技能框架里面把很多單位的表現(xiàn)狀態(tài)(比如替換模型)都抽象成“動作”(而不是單純的骨骼動畫),這種直觀的設(shè)計很舒服。反觀一些方案(比如 unity 很常見的做法)直接把 fbx 作為美術(shù)流水線的終點,局限性很大,加個簡單特效都要放到上層技能框架里,還不能預(yù)覽,最好在裸骨骼動畫和“技能”之間加個支持編輯器預(yù)覽的、引擎實時演算功能(主要是特效、聲音)相關(guān)的中間層,這個中間層的結(jié)果作為“動作”最終暴露給業(yè)務(wù)層,這方面 unreal 做的就比較好,編輯器對 fbx 的二次加工支持預(yù)覽,用起來方便多了。
研究完了會發(fā)現(xiàn)順便把插件接口、游戲錄像(甚至可以做到從錄像中某個點加入扮演某個陣營、網(wǎng)絡(luò)同步、表現(xiàn)信息自動適配機器配置等內(nèi)容還一塊解決了。只不過我個人山寨的時候最后還是把這套方案的一些繁瑣細節(jié)給折中了,最后的結(jié)果很類似 dota2 的技能系統(tǒng),這就不多說了。
一個玩家都能隨意擴展的 moba 技能體系,難道專業(yè)策劃還做不好?這恐怕是做游戲思路的差異吧。再補充個好玩的,之前 war3 平臺的地圖《軍團 td》作者做了個網(wǎng)游夢塔防,在測試中。
具體到編碼細節(jié)我從 war3 時代就開始研究,也山寨過,非三言兩語可以說清楚,但核心思路其實也就上面說的那些。只要把常見技能都親手制作一遍,心中自有定論。雖然說起來簡單,但是如果非要把自己定位到程序、美術(shù)或策劃的立場上,而不是玩家或者 mod 作者,這玩意可能都太復(fù)雜了。
有人說看起來和某些 ai 的設(shè)計有點像?那是當然的,無論是 ai 還是所謂的“技能”,從基礎(chǔ)的 if else 到上層做了一層又一層的抽象,說到底都是無非就是為了控制異步邏輯的復(fù)雜度,手段都差不多。至于游戲 ai 里面的亂七八糟理論,和本主題無關(guān),就忍住不吐槽了,反正也是一個亂象叢生的領(lǐng)域。
實在覺得搞不懂也懶得折騰這么復(fù)雜的東西,就去研究 war3 的 we 編輯器吧。
大體思路就是把持續(xù)性效果、瞬間傷害、生成單位等一些基礎(chǔ)設(shè)施準備好,再設(shè)計出常見技能的技能模板,最后在合理的時間點發(fā)出信號,配合觸發(fā)器或腳本來擴展技能內(nèi)容。
技能模板如果懶得設(shè)計,甚至初始技能每個技能一個狀態(tài)機硬寫好像也沒什么不可以,反正魔獸爭霸那么復(fù)雜的游戲其實基礎(chǔ)技能也沒多少。
未來擴展出來的技能都是這些技能模板的實例,區(qū)別是發(fā)出的信號或觸發(fā)器在腳本層處理不一樣。
魔獸那么多自定義地圖的技能都是這么出來的,復(fù)制一個已有的技能的配置,然后稍作修改,雖然說起來好像有點傻。
還記得當年第一次見 dota 屠夫的鉤子,驚為天人。
要研究 we,ga 也是大本營,只不過現(xiàn)在討論的少了,畢竟老了,都轉(zhuǎn)到 sc 上面去了。
比 moba 的技能還要復(fù)雜?mugen 之類的格斗夠不夠?
b 站的 mugen 專區(qū),大家玩的不亦樂乎,unity 上讀過一些逆向的格斗游戲,做的不錯的比如韓國的網(wǎng)游靈魂之心,用的是狀態(tài)機。國內(nèi)的比如王者之劍、影之刃啥的,其實都很好逆,unity 寫的。unity 平臺還有一個格斗插件寫的也不錯,讀的是早期版本,沒有用狀態(tài)機有點難讀,但很多格斗業(yè)務(wù)邏輯相關(guān)的細節(jié)處理的蠻好,比如技能取消、幀優(yōu)勢(Frame Advantage這么翻譯沒錯吧,街霸的概念)、物理,現(xiàn)在的新版本應(yīng)該更優(yōu)秀吧。
格斗相關(guān)的代碼雖然讀了很多,但是沒有實際做過格斗游戲,不好給更多的參考意見了。
個人的一些反思,可能有點口齒不清亂七八糟 ,對真正做游戲未必有用,放在這里暫記下吧:再復(fù)雜的游戲,所謂的技能,本質(zhì)上是在一段時間線上有撤銷需求、需要強擴展設(shè)計的、分支極為復(fù)雜的、支持配置的異步邏輯,這些異步邏輯之間還可能會有并行交互。更遠一點來看,游戲單位在游戲世界中的存在本身就是狀態(tài)(比如云風的 skynet 游戲服務(wù)器中對每個單位生成一個 luastate 的 agent,配合 coroutine 來實現(xiàn)異步拉成同步不阻塞),很多技能就是單位這個狀態(tài)體生成的子狀態(tài),這樣理解單位的行為(比如 walk、idle,而不單單是通俗意義上的技能)會變得更有意思,仿佛和人類社會一樣,一切都是并行順著時間向前走的,沒有回調(diào)沒有中斷,一切邏輯的上下文變得自然而然(異步的復(fù)雜性很多時候是來源于上下文的丟失)。
如果這套設(shè)想是成立的,簡化異步編程,各行各業(yè)有很多探索,游戲行業(yè)未必就是做得最好的,比如我曾業(yè)余實踐過基于 actor 模型(coroutine模擬的) 的技能框架,雖然很多細節(jié)至今沒能解決,但確實是很有意思的探索。