測試如何在場景切換過程安插工作 – Testing Unity SceneManager Events

最近與朋友討論了如何在 Unity 切換場景完的瞬間,立刻執行某些特定工作。嘗試了幾個方式後,發現基本上是不可能的。不過如果要在Awake 之後, Start 之前進行某些工作,則可以利用 Unity SceneManager 類別底下預設的幾個事件 (Event) 來達成。

不過 Unity 官方文件對於 SceneManager 預設事件的說明可以說是沒有,所以還是得自行測試過才能確定功能。

正好前陣子測試了 MonoBehaviour 時,在轉換場景的部分沒有測試完全,便趁這機會與 Unity SceneManager 一並做些測試,確定在切換場景的過程中所有流程 (Flow),未來依據不同需求便可以在不同階段安插希望執行的工作了。

關於 MonoBehaviour 的測試可以看這篇文章:

本次測試用腳本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneLoader : MonoBehaviour {

    private void Start() {
        GameObject.DontDestroyOnLoad(this.gameObject);
        SceneManager.sceneLoaded += SceneLoaded;
        SceneManager.sceneUnloaded += SceneUnloaded;
        SceneManager.activeSceneChanged += ActiveSceneChanged;
    }

    private void SceneLoaded (Scene scene, LoadSceneMode mode) {
        Debug.Log("SceneLoaded");
    }

    private void SceneUnloaded(Scene scene) {
        Debug.Log("SceneUnoaded");
    }

    private void ActiveSceneChanged(Scene sceneA, Scene sceneB) {
        Debug.Log("ActiveSceneChanged");
    }

    public void ReloadScene() {
        Debug.Log("=== ReloadScene Start ===");
        StartCoroutine(StartLoadScene("main"));
    }

    private IEnumerator StartLoadScene(string sSceneName) {
        AsyncOperation op = SceneManager.LoadSceneAsync(sSceneName, LoadSceneMode.Single);
        while (!op.isDone) {
            yield return null;
        }
        Debug.Log("=== ReloadScene End ===");
    }
}

除了上方的主要腳本,另外場景中還準備了在上週直播時所使用的 TestUnit,用於確認 MonoBehaviour 的事件執行狀況,同時有一個按鈕用於切換動作。

完整的測試專案可以在我的 github 找到,連結如下:

測試結果

scenemanager

假設我們是從場景A切換至場景B,則可以紀錄整個流程為:

=== ReloadScene Start === # Coroutine 的起點
# 場景A 的 OnDisable
# 場景A 的 OnDistroy
SceneUnoaded       # SceneManager 事件
# 場景B 的 Awake
# 場景B 的 OnEnable
SceneLoaded        # SceneManager 事件
ActiveSceneChanged # SceneManager 事件
# 場景B 的 Start
# 場景B 的 Update
=== ReloadScene End === # Coroutine 的終點
# 場景B 的 LateUpdate

從結果可以看出,SceneManager 各個事件的執行時機,以及 MonoBehaviour 的相關事件何時執行。

其中 SceneManager.activeSceneChanged 可能會在切換場景以外的功能觸發,所以建議場景切換時,只要使用 SceneManager.sceneLoaded 以及 SceneManager.sceneUnloaded 就好。

另外可以發現,因為 Coroutine 的運算時間是在 Update 之後,所以收尾的動作會在新場景的物件之 Start 之後執行,並不會在場景切換後立刻執行,這點於開發中相對重要。

後話

這次文章算是把直播所提出的 MonoBehaviour 議題做了一個收尾,也是我第一次使用 SceneManager.sceneLoaded 等事件。

透過這次測試,可以整理出一個簡易的場景切換工具,方便在各個時間點插入工作,用於精確進行新場景的初始化,以及 Loading 畫面的處理等,頗有收穫。

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s