1. 程式人生 > >《爐石傳說》架構設計賞析(1):遊戲啟動流程

《爐石傳說》架構設計賞析(1):遊戲啟動流程

前些天看新聞,Unity Awards兩項大獎頒給了暴雪的《爐石傳說》,這真是對Unity一個再好不過的宣傳了——你看,暴雪都開始用Unity了。大家都知道,目前Unity釋出的遊戲大多都沒有對程式集進行混淆、加密,所以作為一個爐石的玩家&Unity的初學者,自然不能錯過這個機會。讓我們好好看一下暴雪的程式碼吧。

爐石傳說的遊戲內容的非常豐富多彩,所以我花了一些時間分析了其程式集,將一些設計思路記錄下來,與大家分析。歡迎各路高手拍磚,歡迎轉載,請註明出處:燕良@遊戲開發http://blog.csdn.net/neil3d/article/details/39104329

做這些分析的主要目的是:

  1. 看看爐石如何組織遊戲邏輯,以支撐複雜的技能邏輯、表現等;
  2. 看看爐石是如何使用Unity的,其結構設計和技巧上有什麼值得學習的地方;
  3. 向暴雪的程式設計師好好學習一下英語。
下面我們就正式開始。我習慣先分析一下游戲的啟動流程,這中間就涉及到了遊戲基礎資料的管理&初始化,各種管理器級別的類,以及相互引用關係也會初步顯現。

首先看一下我找到的一些遊戲啟動過程相關的類,下面是他們的類圖:


接下來我們分析一下游戲啟動的操作流程。

  • ApplicationMgr物件應該繫結到了一個場景物件中,這個場景應該在遊戲啟動中載入;
  • ApplicationMgr:Awake()被Unity引擎自動呼叫;
    • 呼叫ApplicationMgr:Initialize(),在這個函式中順序呼叫了以下成員函式來進行初始化:
      • InitializeMode():設定模式為ApplicationMode.PUBLIC;
      • InitializeUnity():設定了UnityEngine. Application的一些屬性;
      • InitializeGame():看來核心的內容在這裡,初始化Network,GameMgr等;
      • InitializeWindowTitle();
      • InitializeOptionValues();
遊戲啟動應該不只這點東西。由於我們純靠程式集的動態分析,無法知道它的場景編輯、物件的指令碼繫結,也不能跟蹤除錯,所以只能靠猜測了。另外,一些事件是通過網路訊息觸發的,這也給靜態分析帶來了一些難度。 OK,我們繼續。我注意到了class Login,它從Scene派生。查看了一下Scene的派生類還有不少,我猜測每個派生類,作為特定Scene邏輯處理的指令碼。而Login應該是在第0個場景中被啟用執行。我們看一下Login:Start(),這屬於MonoBehavior自動呼叫,他主要做了這樣幾件事:
  • 註冊了一些資源版本檢測、Login相關的網路訊息回撥;
  • 通知SceneMgr場景載入完成;
  • 呼叫成員函式:AutoLogin();此函式呼叫Network.AutoLogin();
    • 從配置檔案中找到User Name,然後呼叫ConnectAPI.AutoLogin()——奇怪的是發現這個函式只是簡單的返回false,並沒有進行實際的操作。
我們在來看一下Login:Update(),這個也是屬於被自動呼叫的指令碼函式。在這裡它檢測了Login的狀態,並呼叫了成員函式LoginOk(),而它有主要呼叫了AssetsVersionCheckCompleted(),這個函式內容很豐富:
  • 通知其他模組,已經登入成功,包括:BaseUI、 InactivePlayerKicker、HealthyGamingMgr、GameMgr
  • 呼叫一些模組的Initialize函式,包括:DefLoader、CollectionManager、AdventureProgressMgr、Tournament、StoreManager等;
我們前面看到了Login從Scene派生,並且還有一個SceneMgr類。我們可以斷定遊戲根據不同的邏輯劃分成了一些scene,接下來我們就探索一下Scene切換的流程。還是從Login入手。
以下流程都是在Login類中完成,下面描述的過程都是Login成員函式的呼叫:
  • 首先我找到了Login:OnNetCacheReadyStep2()函式,這個應該是login流程中某一步的網路訊息回撥函式;
  • 它會呼叫 WaitForAchievesThenInit()這個Coroutine函式,這個函式檢測了是否需要播放視訊,然後呼叫ReconnectOrChangeMode();
  • 此函式處理重新連線,一般的話應該是呼叫了ChangMode();
  • ChangMode()處理了新手教程相關的啟動邏輯,一般的話會呼叫ChangeMode_Hub();
  • 這個地方貌似是呼叫了一個技能特效,特效播放完成之後呼叫回撥函式:OnStartupHubSpellFinished();
  • 此函式呼叫ShowUnAckedRewardsAndQuests();
  • 這裡面主要是呼叫了HandleUnAckedRewardsAndCompletedQuests(),哦~,這應該是遊戲啟動的時候顯示當前任務還有未領取的獎勵的那個介面
  • 它會呼叫ShowNextUnAckedRewardOrCompletedQuest();
  • 其中主要呼叫了ShowWelcomeQuests();
  • 當幸虧顯示的任務為0時,則呼叫了這一句:SceneMgr.Get().SetNextMode(SceneMgr.Mode.HUB),這是關鍵的一步了;
接下來就我們跳轉到SceneMgr類中,繼續探索Scene切換流程的實現。以下都是指的SceneMgr的成員函式:
  • SetNextMode()函式主要就是把“m_nextMode”成員變數設定為了指定值;
  • 接下來看一下Update(),這個函式主要是檢測了是否需要切換Mode,然後呼叫了:
    • SwitchMode():這個是一個Coroutine,它主要是呼叫了LoadModeFromModeSwitch(),它的核心也是呼叫LoadMode();
    • 直接呼叫LoadMode()
  • LoadMode()函式,主要是根據當前的Mode,呼叫LoadScene();
  • LoadScene()函式主要是呼叫了: Application.LoadLevelAdditiveAsync(this.sceneName);
  • 這樣就完成了場景的切換。
OK。通過以上分析,我們大體瞭解了遊戲啟動過程是這樣的:
  • 進行賬戶驗證;
  • 賬戶驗證完畢之後,顯示未領取的獎勵和任務;
  • 然後切換到SceneMgr.Mode.HUB模式,即載入了相應的Scene。
關於遊戲啟動的分析告一段落,下一篇將會分析一下爐石的Scene組織。