一:Unity ACT技能編輯器的製作(下)

一:Unity ACT技能編輯器的製作(下)

來自專欄 Unity 遊戲開發總結

接上半部分,再分享一些:

  • 序列化數據
  • SkillCtrl 和 Trigger的設計
  • 編輯器和excel表數據的配合
  • 一些做得還不夠好的地方,以及一些思考

以下內容,提到的"招式"和「技能」基本上是同一個意思。但是和傳統遊戲,也有些不同。

可以理解為,傳統遊戲一個技能,分四段攻擊,可能對應我們的四個招式。


  • 序列化數據

編輯器,最重要的是數據的讀寫,也就是序列化和反序列化。

之前已經說明,我不使用scriptobject和prefab上掛MonoBehaviour來序列化數據的原因,不再贅述。

現在放在手邊的選擇有兩個,一種是序列化為文本(xml,json),一種是序列化為bytes。

我最先是序列化為xml,因為我認為xml比json可讀性強一些,剛開始我可以先手動寫一個xml數據,Deserialize為對應的class,等編輯器基本成型以後,再補上Serialize即可。

這樣,我只需要設計一個根據tag反射來自動化處理的方式即可(當時沒仔細找,應該此方式有現成方案)。

通過tag,可以寫一套通用的序列化反序列化處理

xml序列化在前期的好處是,編輯器不穩定,數據經常錯誤報錯,可以手動修改xml的數據,方便測試編輯器bug,以及調試功能。xml還有很好的可讀性,以及版本管理方便merge。

但是當我們編輯器穩定後,xml的劣勢就顯現了:

  1. 序列化反序列化性能差
  2. 需要給一些不支持string化的數據做支持(color,curve等)
  3. 序列化依賴變數name,如果我們重構改了變數名(重構名字是常事),數據就丟失了

所以,後面,經過調研,我們選擇了用protobuf來做序列化,直接解決了1,3的問題。需要了解protobuf詳情的請自行google。

protobuf來序列化,protobuf的tag

對於2裡面的問題,需要做一些處理,將其protobuf化

將color protobuf化

PBColor的使用

再結合AdvancedInspector插件(後面介紹)來使inspector下支持和原來一樣的顯示

至此,基本上解決了序列化和反序列化的問題,最後我們將每一個角色數據,序列化,存為一個.bytes文件。(帶來的副作用,即不方便merge,這裡只有策劃通過規範提交修改的流程,減少衝突,目前我們遇到很少)

一個角色對應一個文件,由編輯器讀寫

配合AdvancedInspector提供的UDictionary,我們可以方便地做dictionary的序列化

UDictionary

UDictionary的使用

到此,我們需要介紹一下,幫了大忙的插件Advanced Inspector(現在似乎有了更好的Odin):

Advanced Inspector - Asset Store?

assetstore.unity.com圖標

具體使用我就不說了,大家可以去看他的sample,對於在Inspector上做東西,方便很多很多。

  • SkillCtrl 和 Trigger的設計

上一篇提到過,在總體設計好之後,新加的技能方面的功能,主要集中在SkillCtrl 和 Trigger的添加。

這裡在語義上是:當XXX的時候,執行YYY。 XXX就是Trigger,YYY就是SkillCtrl 。比如策劃可以配置:

  • 當0~10幀時,播放技能特效
  • 當10~20幀時,並且是擊中狀態,播放技能特效
  • 當20~30幀時,震動屏幕
  • 當20~30幀時,角色在浮空狀態,添加人物殘影
  • 等等

在設計上,SkillCtrl和Trigger,都是這樣:

1.定義一個TriggerType

Trigger enum

2. 定義Trigger的基類

Trigger base

3.之後擴展,就是繼承基類,加上配置數據,override isTrigger方法,處理自己的條件邏輯

Trigger implement

SkillCtrl,主要包含一列Trigger,所有的Trigger都為true,就返回true。這裡沒有設計or的邏輯方式,Trigger之間,都是and的方式。

對應Runtime邏輯,一個SkillCtrl cfg,對應一個ctrler

runtime ctrler base

擴展的時候,實現對應的ctrler即可

對應的播放聲音 ctrler

大部分遊戲,需要設置邏輯主循環,在每一個logic tick,去檢查Trigger,Trigger都為true,執行對應的ctrler,即可。這裡的logic tick,即對應編輯器裡面的一個幀,同一概念。

接下來是一些小的點:

  1. 這裡有一個小trick,就是類命名用"_"分隔,前半部分一樣,後半部分區分具體實現,可以通過反射來獲得instance類,以免做工廠,或者switch case。

ActorSkillCtrlerCfg_Base cfg = U3DUtil.CreateClassByBaseType<ActorSkillCtrlerCfg_Base>(ctrlType);

2. 在這樣設計的過程中,遇到了一個問題,就是unity的inspector。聲明是base class,但是賦值了child class,unity的inspector還是顯示base class 的數據。

例如我希望在編輯器里點任何一個ctrler,都顯示對應ctrler類型的數據

資源的ctler

對應的代碼

unity默認的inspector,只會顯示申明的類型ActorSkillCtrlerCfg_Base,而不會顯示對應的特效數據

這裡解決方案很簡單,引入Advanced Inspector即可,插件能自動顯示真實type的數據,這是Advanced Inspector幫助解決的最大的問題。

思考:每一個功能模塊,我們要處理好完全不設計和過度設計的平衡,特別是一開始,不要過度設計。花時間理順需求,盡量找准擴展點,把擴展點處理好,後續就是往上搭積木了。這個過程中,必然經歷幾次重構和優化,沒有一次就做好的設計,重構是程序的核心技能。

  • 編輯器和excel表數據的配合

當我們開發demo的時候,儘可能求快。角色的數據,我們就直接在編輯器里配了,比如攻防血,技能每一個hit的傷害,招式的cd,消耗的sp等,也並未考慮招式升級了,基礎傷害提升等,這些也不是編輯器應該關心的邏輯。

當項目正式化之後,我們需要解決的,就是數據,策劃是配置在excel里的,我們需要整合excel數據和編輯器數據。

對我們來說,比較麻煩的是,我們結算傷害,並不是以一個技能為一個單位,而是以每一個hit,一個技能,策劃可能配置多個atkBox,一個atkBox,可能產生多次hit,但是,我們不可能給每個hit配置一個傷害,數值策劃配置到這麼細,他們會崩潰。所以,策劃的excel表,是以技能(招式)為單位,配置一個傷害

數值配一個角色,某一個招式動作的總傷害數值

而技能編輯策劃,在技能編輯器里,配置每一個hit,對應這個傷害的百分比

比如這個招式,策劃配整體傷害1000,某個hit這裡配置0.4,最終結果就是1000*0.4 = 400

通過這種方式,將數值策劃從編輯器中解脫出來,他們無需關心有幾個hit,只需要處理整體效果,技能編輯策划去將所有hit的係數分割。

當然,我們數值計算很複雜,這只是初步基礎數值。

思考:這裡,其實是想說,將邏輯和數值分開來,各自關心各自的東西。這樣,我們將prefab(view),邏輯(技能邏輯),數值(excel配表)都區分開來,按照一定的規則,在runtime時候結合。

  • 一些做得還不夠好的地方,以及一些思考

說點遺憾和不夠好的地方吧:

  1. 沒有做整體的undo和redo功能,因為做demo的時候,整體只有兩周,實際大概一周半做完,沒有時間設計整體的undo,redo。後續根據策劃需求,解決了部分copy,paste,以及依靠Advanced Inspector的功能,做到了inspector部分的copy,paste,也算基本不影響策劃的使用。但任然算是一個不足
  2. 戰鬥整體預覽,做得不夠完整。目前在播放器里,可以在play 招式的時候,對應播放特效,聲音,但是不能所有skillCtrl整體模擬。 之前想過在editor裡面跑一個簡單的runtime battle,只包含當前編輯的角色,和一個npc,讓編輯和預覽能夠無縫銜接,但是處理起來,有點麻煩。 現在的做法是,在runtime 的gm菜單中,給個介面,打開技能編輯器,編輯完,保存以後,將runtime cache的配置清空,重新打開戰鬥,選定的角色就會重新load 新保存的配置。雖然不夠完美,也很大提高了策劃的速度(以前編輯好一個,需要重新run 遊戲,現在可以在遊戲中實時更改,再進入戰鬥就更新),幫助策劃提高工作效率,是程序責無旁貸的責任,我們動動手,策劃抖兩抖。
  3. 有些部分設計得不夠友好,策劃配起來,有點蛋疼。例如配置子彈的邏輯,目前做的不夠好。

我不想做一個大而全的,能通用的編輯器,我只想理順思路,當我們下次做項目,或者類似東西的時候,能夠在現有的基礎上,通過裁剪和重構,快速得到一個符合項目需求的編輯器。(所以我的編輯器,不做任何unity版本兼容)

現有編輯器,可以支持格鬥,Act,arpg類遊戲,如果做mmo和rpg,那就要裁剪到過於複雜的部分,簡化即可。如果做點跑酷呢?那要這編輯器就沒意義了,一切都要根據自己的項目來,不是越強大越好。

最後,開個務虛生活會:

  • 當我們需要快速出demo的時候,更應該理順思路再動手,切忌上來就編碼。把可能的難點先測試搞定,之後就順手了
  • 重構,不要怕重構,在合適的時間,做合適的重構,是我們程序的核心技能
  • 組織好數據,讓數據和美術資源分離,不要讓美術資源的變化,干擾你處理數據的工作流。
  • 策劃是弱勢群體,能幫一把是一把,幫助他們提升效率,是程序能力的體現。
  • 做編輯器,要站在策劃的角度,他們是用戶,自己要用,才會發現問題,Eating our own dog food。

下期預告:還沒想好~

推薦閱讀:

C#代碼跟unity關聯教程
一種unity Android集成SDK的方式
使用頂點投射的方法製作實時陰影
如何實現切割一張圖片?
Unity中的單例模式、回調函數、消息分發的使用區別?

TAG:遊戲開發 | Unity遊戲引擎 | unity |