GameFramework食用指南

小紫蘇發表於2022-07-01

1.框架簡介

GF框架分兩部分,GameFramework(GF)和UnityGameFramework(UGF);

通過介面的形式對Unity引擎進行了解耦;

GF獨立於Unity,具體業務邏輯實現都在GF中;

UGF是繼承了MonoBehaviour的元件,通過介面呼叫GF中Module的方法;

框架流程

左邊GF層,由GameFrameworkEntry管理所有GameFrameworkModule;(使用GF自己實現的連結串列非list)

Update階段根據每個Module的Priority順序輪詢執行所有Module的Update;

GameFrameworkEntry對外提供獲取單個Module的方法;

右邊UGF層,UGF中所有Component都繼承GameFrameworkComponent;

GameFrameworkComponent做兩件事:

  • 繼承MonoBehaviour,未每個元件提供UnityComponent的生命週期;
  • Awake方法中註冊該UGF元件,將所有UGF元件儲存在UGF層的GameEntry類中;

UGF中的BaseComponent,Awake階段做Text,Log,版本,json輔助器的初始化;

Update階段呼叫GF層的GameFrameworkEntry的Update方法,輪詢實行所有GF層Module的Update;

BaseComponent還提供推出程式,重啟暫停遊戲的方法;

UGF層的GameEntry:

上文提到,所有的UGF元件都繼承GameFrameworkComponent;

GameFrameworkComponent的Awake階段呼叫GameEntry的RegisterComponent方法,儲存UGF元件;

E大官方文件建議,在實際遊戲開發階段,對UGF的GameEntry再做一層封裝——業務層的GameEntry;

將所有用到的UGF元件建立靜態只可get的屬性,只有業務邏輯中只需要通過業務層GameEntry中的靜態屬性來獲取UGF元件;(官方Starforce名稱空間下的GameEntry)

介面解耦

GFModule繼承對應Module的介面,實現具體方法;

UGF組合對應元件介面,Awake階段對介面初始化,通過介面呼叫GF方法;

以ConfigComponent為例:

ConfigManager實現IConfigManager介面方法;

ConfigComponent組合IConfigManager變數,在Awake階段用GF層的ConfigManagerModule初始化;

2.資源管理

GF框架的資源管理非常強大,整合了VFS系統效率高,編輯器擴充管理打包資源清晰明瞭;

Package單機模式:無法熱更;

Updatable可更新模式:遊戲開始前更新完進入遊戲;

Updatable while playing可更新分包載入:遊戲執行時需要使用資源時即時下載;

Config下ResourceBuilder.xml儲存了打包介面的設定資訊;

ResourceEditor.xml設定了ResourceEditor介面中可被打包的資源格式,過濾所有指令碼,同時設定了資源編輯介面的搜尋路徑;

ResourceCollection.xml記錄了所有ab包,以及資源依賴;

介面操作GF的官方文件寫的非常詳細,這裡介紹一下資源熱更流程;

熱更流程

Resource節點選擇Updatable,GameFramework節點關閉EditorResourceMode;

ResourceBuilder打包勾選OutputFullPath;

修改GameMian/Configs/BuildInfo.txt中CheckVersionUrl;

打包輸出路徑找到對應打包版本的BuildLog.txt,找出加密hash;

打包輸出路徑/Full/1_0_0(對應版本)下,建立version.txt,本地伺服器也搭建在這個位置;

{
"ForceUpdateGame": false,                                
"LatestGameVersion": "1",                                
"InternalGameVersion": 0,
"InternalResourceVersion": 1,
"UpdatePrefixUri": "http://localhost:8888/Windows",        //資源伺服器地址
"VersionListLength": 3280,                                //BuildLog中的加密hash
"VersionListHashCode": -553090012,        
"VersionListCompressedLength": 1326,
"VersionListCompressedHashCode": 1159160375,
"END_OF_JSON": ""
}

更新時比對LatestGameVersion和InternalGameVersion,確定是否更新;

一定要刪除本地快取的persistantData路徑下的檔案;

3.資料表

GF的DataTable預設excel複製下來的結構,像CSV但分隔符是/t;

直接用DataTable元件根據行數載入單條資料;

支援bytes和json格式;

Configs中DataTableCodeTemplate,用於生成C#類别範本;

怎麼說呢,簡單遊戲夠了,複雜點的還是加個導表工具或者魔改一下;

DataTable也可以新增自定義資料解析;

另外直接在txt中新增資料條總是莫名奇妙的格式錯誤,畢竟空格肉眼也區分不了;

我改成, 分隔後,註釋列又顯得很多餘;

所以我根據GF的原理自己誰先了直接讀Excel的DataTable,支援json和bytes;

一鍵匯出,且自動生成c#類,支援陣列和列舉,支援excel公式;

Excel導表工具

4.事件系統

GF的事件系統是基於引用池的,每次回收前需要Clear資料,防止髒資料;

註冊和取消註冊

GameEntry.Event.Subscribe(TestArgs.EventId, OnTest);
GameEntry.Event.Unsubscribe(TestArgs.EventId, OnTest);

自定義事件類

public class TestArgs:GameEventArgs
{
    public static readonly int EventId = typeof(ResourceVerifyStartEventArgs).GetHashCode();

     public override int Id
    {
         get
         {
             return EventId;
          }
    }

     public override void Clear()
    {
      }

    //以上部分是必須有的部分,以下屬於自定義,事件需要傳遞的引數都可以寫在下面,相應的Clear中需要清空
}

事件傳送

GameEntry.Event.Fire(object sender,new TestArgs());

sender傳送人,一般填this;

第二引數,具體事件類,如果有引數,需要先賦值,個人喜歡寫帶參構造,也可以單獨寫Init函式;

事件響應

public void OnTest(object sender, GameEventArgs e)
{
    TestArgs en = (TestArgs)e;
    //執行邏輯
}

5.流程控制

GF框架使用流程控制來控制遊戲階段;

流程控制元件是一個被固定了擁有者(ProcedureOwner)的狀態機(FSM);

通過狀態機來控制更新,載入,初始化等;

這裡的流程不指遊戲中具體業務邏輯流程;

StarForce中的流程控制;有問題打個斷點總能看清楚的;

切換場景GF時切換到changeScene流程解除安裝資源後載入新場景流程;

6.UI模組

GF的UI分為UIGroup和UIForm;

UIGroup中包含多個UIForm,由UIGroup管理其中的UIForm;

UIForm的層級等於所屬UIGroup層級自身層級(SortOrder);

UIGroup概念有點想UI中的預設層,Pop層,前景層,背景層,可自定義;

在場景UI節點新增UIGroup;

所有UI指令碼必須繼UGuiForm,UGuiForm繼承UIFormLogic,UGuiForm中對所有Text做了本地化處理;

UI生命週期:

UI的層級問題:

每個UIGroup要求設定order層級;

每個UIForm的層級最終是自身sortorder+所屬group的order;

在建立預製體時可設定好;

7.Entity模組

Entity個人理解相當於自己封裝了一個MonoBehaviour類,但是還整合了Mono;

同時有GF的生命週期+Mono的生命週期;

Enity包括了GameObject的功能,由GF的EntityModule來控制Active;

Entity也是基於物件池的,從框架層管理記憶體問題;

使用

邏輯控制類繼承EntityLogic,重寫其中生命週期的方法(別忘記base.);

顯示Entity呼叫GameEntry.Entity.ShowEntity(id,path,group);

id在datatable中配置;

path為datatable中配置的預設路徑+AssetName;(ResourceEditor介面的path)

Entity中提供了Attach方法;

通過GameEntry.Entity.AttachEntity()呼叫,此時會呼叫父物體EntityLogic中OnAttached週期,和子物體OnAttachTo週期;

解綁時呼叫OnDetached,OnDetachFrom;

Entity和EntityLogic

預製體不需要綁EntityLogic指令碼,ShowEntity時會自動綁上EntityLogic+Entiy指令碼;

這倆指令碼相互引用,Entity的週期中都在呼叫EntiyLogic對應的周期函式;

Entity繼承自IEntity,被EntityComponent管理;

小聲比比:所以,這兩個有一個就行,或者Entity其實不用繼承Mono;

具體操作時,只寫EntityLogic指令碼,不用管Entity;

8.FSM有限狀態機

GF的狀態機都由FsmComponent管理(GameFrameworkComponent);

建立狀態機時,需要狀態機的Owner(泛型T),和FsmState陣列;

eg:Hero繼承EntityLogic

ActBase<Hero>[] array = new ActBase<Hero>[] { new IdleAct<Hero>(), new RunAct<Hero>() };
mFsm = GameEntry.Fsm.CreateFsm<Hero>(this, array);

public class IdleAct<T>:ActBase<T> where T : Hero
{
    protected override void OnInit(IFsm<T> fsm)
    {
        base.OnInit(fsm);
    }
    protected override void OnEnter(IFsm<T> fsm)
    {
        base.OnEnter(fsm);
        fsm.Owner.PlayCurAnima();
    }
    
    protected override void OnUpdate(IFsm<T> fsm, float elapseSeconds, float realElapseSeconds)
    {
        base.OnUpdate(fsm, elapseSeconds, realElapseSeconds);
        if (fsm.Owner.curState == ActState.Run)
        {
            ChangeState<RunAct<T>>(fsm);
        }
    }
}

9.本地化工具

GF的Localization儲存的xml;

UI的Init階段遍歷所有元件,獲得所有Text元件,根據Text元件中的text載入本地化語言,同時設定對應字型;

該語言=重新載入遊戲;

這個元件簡單但不夠智慧;

個人新增了兩個功能:

  • 根據TextMeshProGUI元件的Name和text內容自動新增簡體中文多語言xml的key;

  • 呼叫谷歌介面自動翻譯,生成其他語言xml;

Localization.cs

相關文章