《爐石傳說》架構設計賞析(2):Scene管理
阿新 • • 發佈:2018-11-16
歡迎來的我的酒館,快來火爐旁暖暖你的靴子。哈哈,我們繼續欣賞爐石的程式碼。歡迎轉載,請註明作者【燕良@遊戲開發】及原文地址:http://blog.csdn.net/neil3d/article/details/39231541
上篇文章我們分析到SceneMgr處理了Scene的載入工作,今天我們主要分析一下爐石這款遊戲中一共有哪些Scene,他們各自負責什麼,以及它內部的邏輯、UI的處理方式。
在正式開始之前,我來對前文中提到的Scene切換再做一些補充分析。前文中我們看到SceneMgr是呼叫了“ Application.LoadLevelAdditiveAsync(this.sceneName);”,那記憶體中的東西豈不是越搞越多嗎?我們再仔細看一下SceneMgr:SwitchMode()函式,它是一個Coroutine,他主要進行了下面這幾個步驟的操作:
- 呼叫當前Scene的Scene:PreUnload()函式;
傳送FireScenePreUnloadEvent事件;
等待直到Unload過程走完(通過檢測LoadingScreen的階段); - 呼叫Scene:Unload()函式;
傳送FireScenePreUnloadEvent事件;
呼叫成員函式PostUnloadCleanup()函式,它呼叫了兩個關鍵的函式:- 首先是成員函式:DestroyAllObjectsOnModeSwitch(),這個函式查詢到所有的GameObject(Object.FindObjectsOfType(typeof(GameObject))),然後進行了篩選(通過成員函式ShouldDestroyOnModeSwitch),除了一些全域性物件之外(主要是SceneMgr、PegUI、Box、DefLoader),全都刪除了(通過呼叫Object.DestroyImmediate())。
- 然後呼叫了:Resources.UnloadUnusedAssets();
- 首先是成員函式:DestroyAllObjectsOnModeSwitch(),這個函式查詢到所有的GameObject(Object.FindObjectsOfType(typeof(GameObject))),然後進行了篩選(通過成員函式ShouldDestroyOnModeSwitch),除了一些全域性物件之外(主要是SceneMgr、PegUI、Box、DefLoader),全都刪除了(通過呼叫Object.DestroyImmediate())。
- 然後是呼叫前文提到過的成員函式:LoadModeFromModeSwitch(),進行了LoadLevelAdditiveAsync()操作;
除了前文提到的Login,我們可以看到Scene還有很多派生類,詳見下圖:
這是我猜測的這些類和遊戲內容的對應關係,沒有太仔細分析,可能有些對應是錯誤的:
下面我們就挑選一個簡單的Scene來分析一下它的內部運作機制,我們來看一下AdventureScene吧。Adventure相關的Class很多,我們只做一個粗略的分析,只涉及到下面這幾個類和介面:
首先我推測,在Hub螢幕中點選中間的【Solo Adventure】(冒險模式)按鈕之後,通過我們前文分析的LoadScene流程,載入了一個冒險模式相關的Scene。它裡面有一個GameObject綁定了“AdventureScene”這個指令碼,我們可以看到AdventureScene:Awake()方法中主要是註冊了很多事件的回撥。 我們可以看到有一個“AdventrueSubScenes”列舉,它基本上對應了下圖中的按鈕:
public enum AdventureSubScenes
{
Chooser,
Practice,
MissionDeckPicker,
NormalHeroic,
ClassChallenge
}
接下來還有一個"AdventureSubScene"是處理子場景對應的一些邏輯的。
我們看到有“AdventureChooserTray”這個類:
- 我推測這個類就是用來處理上面這個遊戲畫面的UI互動操作的;
- 這個類在Awake時,通過呼叫“CreateAdventureChooserButton()”方法建立了上圖中的上部分那幾個冒險遊戲內容模式相關的按鈕;
- 這些按鈕都綁定了事件回撥:AdventureChooserTray.ButtonModeSelected();當這些按鈕被點選時,主要是呼叫:
- AdventureConfig:SetSelectedAdventureMode(),此函式修改內部資料之後觸發事件:FireSelectedModeChangeEvent()
- AdventureChooserTray通過OnSelectedModeChange()響應此事件,這也就是點選上面那幾個按鈕之後要做的一些處理:包括更新左側的畫面、設定Choose按鈕狀態等等;
其中呼叫了PlayMakerFSM,主要是向其傳送事件“Burst”;通過這裡,我們可以確定爐石使用了PlayerMaker外掛。 - AdventureScene也通過OnSelectedModeChanged()相應了此事件;
- AdventureConfig:SetSelectedAdventureMode(),此函式修改內部資料之後觸發事件:FireSelectedModeChangeEvent()
- 它裡面還有一個“PlayButton m_ChooseButton”成員變數,並把為它添加了EventListener,用來呼叫ChangeSubScene()方法。這就和遊戲實際的操作對應上來:在上面選擇模式,然後點選下面的【Choose】按鈕,就進行到下一步的選擇了。
- AdventureChooserTray:ChangeSubScene()通過Coroutine的方式呼叫了AdventureConfig:ChangeSubSceneToSelectedAdventure(),然後呼叫了AdventureConfig:ChangeSubScene();它主要觸發兩個事件:
- FireSubSceneChangeEvent:AdventureScene通過OnSubSceneChange()函式響應它,主要是呼叫AdventureScene:LoadSubScene(),內部主要是呼叫AssetLoader.LoadUIScreen();
- FireAdventureModeChangeEvent:AdventureScene通過OnAdventureModeChanged()響應它。
- 遊戲邏輯的組織,特別是技能的資料、邏輯組織;這可能需要經過多次嘗試,慢慢接近;
- 遊戲的Asset資源管理、載入機制;