《炉石传说》架构设计赏析(2):Scene管理
今天我們主要分析一下爐石這款游戲中一共有哪些Scene,他們各自負責什么,以及它內部的邏輯、UI的處理方式。
在正式開始之前,我來對前文中提到的Scene切換再做一些補充分析。前文中我們看到SceneMgr是調用了“Application.LoadLevelAdditiveAsync(this.sceneName);”,那內存中的東西豈不是越搞越多嗎?我們再仔細看一下SceneMgr:SwitchMode()函數,它是一個Coroutine,他主要進行了下面這幾個步驟的操作:
1.調用當前Scene的Scene:PreUnload()函數;
發送FireScenePreUnloadEvent事件;
等待直到Unload過程走完(通過檢測LoadingScreen的階段);
2.調用Scene:Unload()函數;
發送FireScenePreUnloadEvent事件;
調用成員函數PostUnloadCleanup()函數,它調用了兩個關鍵的函數:
- 首先是成員函數:DestroyAllObjectsOnModeSwitch(),這個函數查找到所有的GameObject(Object.FindObjectsOfType(typeof(GameObject))),然后進行了篩選(通過成員函數ShouldDestroyOnModeSwitch),除了一些全局對象之外(主要是SceneMgr、PegUI、Box、DefLoader),全都刪除了(通過調用Object.DestroyImmediate())。
- 然后調用了:Resources.UnloadUnusedAssets();
3.然后是調用前文提到過的成員函數:LoadModeFromModeSwitch(),進行了LoadLevelAdditiveAsync()操作;
綜上所述,爐石的Scene切換主要是包含兩步:1刪除所有非全局對象,卸載未引用的Asset;2加載新的Scene。(我倒是想到另外一個土鱉一點的替代方案:創建一個完全空的scene,調用LoadLevel加載它,那么所有沒有設置"DontDestroyOnLoad"的對象就都被刪除了。)
除了前文提到的Login,我們可以看到Scene還有很多派生類,詳見下圖:
?
這是我猜測的這些類和游戲內容的對應關系,賣二手游戲平臺沒有太仔細分析,可能有些對應是錯誤的:
下面我們就挑選一個簡單的Scene來分析一下它的內部運作機制,我們來看一下AdventureScene吧。Adventure相關的Class很多,我們只做一個粗略的分析,只涉及到下面這幾個類和接口:
?
首先我推測,在Hub屏幕中點擊中間的【Solo Adventure】(冒險模式)按鈕之后,通過我們前文分析的LoadScene流程,加載了一個冒險模式相關的Scene。它里面有一個GameObject綁定了“AdventureScene”這個腳本,我們可以看到AdventureScene:Awake()方法中主要是注冊了很多事件的回調。
我們可以看到有一個“AdventrueSubScenes”枚舉,它基本上對應了下圖中的按鈕:
?
接下來還有一個"AdventureSubScene"是處理子場景對應的一些邏輯的。
我們看到有“AdventureChooserTray”這個類:
1.我推測這個類就是用來處理上面這個游戲畫面的UI交互操作的;
2.這個類在Awake時,通過調用“CreateAdventureChooserButton()”方法創建了上圖中的上部分那幾個冒險游戲內容模式相關的按鈕;
3.這些按鈕都綁定了事件回調:AdventureChooserTray.ButtonModeSelected();當這些按鈕被點擊時,主要是調用:
?
- AdventureConfig:SetSelectedAdventureMode(),此函數修改內部數據之后觸發事件:FireSelectedModeChangeEvent()
- AdventureChooserTray通過OnSelectedModeChange()響應此事件,這也就是點擊上面那幾個按鈕之后要做的一些處理:包括更新左側的畫面、設置Choose按鈕狀態等等;
- 其中調用了PlayMakerFSM,主要是向其發送事件“Burst”;通過這里,我們可以確定爐石使用了PlayerMaker插件。
- AdventureScene也通過OnSelectedModeChanged()相應了此事件;
4.它里面還有一個“PlayButton m_ChooseButton”成員變量,并把為它添加了EventListener,用來調用ChangeSubScene()方法。這就和游戲實際的操作對應上來:在上面選擇模式,然后點擊下面的【Choose】按鈕,就進行到下一步的選擇了。
5.AdventureChooserTray:ChangeSubScene()通過Coroutine的方式調用了AdventureConfig:ChangeSubSceneToSelectedAdventure(),然后調用了AdventureConfig:ChangeSubScene();它主要觸發兩個事件:
?
- FireSubSceneChangeEvent:AdventureScene通過OnSubSceneChange()函數響應它,主要是調用AdventureScene:LoadSubScene(),內部主要是調用AssetLoader.LoadUIScreen();
- FireAdventureModeChangeEvent:AdventureScene通過OnAdventureModeChanged()響應它。
通過上面的分析,我們大致了解了上面這個游戲截圖中的操作實現邏輯。
這次的分析算是一次熱身,接下來重點分析有兩個方面:
?
- 游戲邏輯的組織,特別是技能的數據、邏輯組織;這可能需要經過多次嘗試,慢慢接近;
- 游戲的Asset資源管理、加載機制;
OK,今天的分析就到這里,歡迎大家拍磚。后續分析敬請期待!
順便來秀一下我的魚人部隊,別看這些1點學的小東西,加在一起還蠻歡樂的!
?
總結
以上是生活随笔為你收集整理的《炉石传说》架构设计赏析(2):Scene管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《炉石传说》架构设计赏析(3):Game
- 下一篇: 该如何在后期处理中,实现高亮描边的效果?