Unity 摧毀 DontDestroyOnLoad 遊戲物件
分類
說明
在 Unity 只要調用 DontDestroyOnLoad(gameObject)
,gameObject
就不會因為切換場景而被摧毀,但問題是如果又想摧毀 gameObject
該怎麼辦?本篇將告訴大家我是如何摧毀的。
DontDestroyOnLoad 簡述
如果調用 DontDestroyOnLoad(gameObject)
,你會在場景中看到新增一個 DontDestroyOnLoad 場景,在這個場景中的遊戲物件不會因為載入新場景 SceneManager.LoadScene("NewScene");
而被摧毀。
找不到內建的解除 DontDestroyOnLoad
上網查了如何解除 DontDestroyOnLoad,但很可惜沒有找到相關的方法可用。
GetSceneByName 方法無效
我嘗試取得 DontDestroyOnLoad 場景的遊戲物件
Scene scene = SceneManager.GetSceneByName("DontDestroyOnLoad");
if (scene.isLoaded)
{
// 進不來這裡
}
如上,就算我不判斷 scene.isLoaded
,硬要取得裡面的遊戲物件也會發生錯誤,具體為什麼會錯誤我也不太清楚,我只能先放棄這個方向了。
摧毀 DontDestroyOnLoad 遊戲物件的方法
摧毀 DontDestroyOnLoad 場景的遊戲物件有兩種方法。
- 直接取得遊戲物件使用
Destroy
方法摧毀。 - 將 DontDestroyOnLoad 場景的遊戲物件,搬移到 DontDestroyOnLoad 場景之外。
上述兩個方法都需要先取得遊戲物件才行。
實作 Destroyer
根據上面的資訊,最後我實作 Destroyer 專門用來摧毀 DontDestroyOnLoad 遊戲物件,原理很簡單將要 DontDestroyOnLoad 遊戲物件存取在 Destroyer 的 indestructibleGameObjects
變數中,統一管理不會被摧毀的遊戲物件,之後想要怎麼摧毀都好處理。
如果只有極少個遊戲物件要摧毀,你可以直接取得遊戲物件使用 Destroy
方法摧毀會比較省事。
Destroyer.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 用來摧毀 DontDestroyOnLoad 遊戲物件
/// </summary>
public class Destroyer : MonoBehaviour
{
/// <summary>
/// 單例實體
/// </summary>
private static Destroyer instance;
/// <summary>
/// 被加入在 DontDestroyOnLoad 的遊戲物件
/// </summary>
private static List<GameObject> indestructibleGameObjects;
/// <summary>
/// 單例實體
/// </summary>
public static Destroyer Instance
{
get => instance;
}
private void Awake()
{
if (instance != null)
{
Destroy(gameObject);
return;
}
instance = this;
DontDestroyOnLoad(instance);
indestructibleGameObjects = new();
}
/// <summary>
/// 同 DontDestroyOnLoad 但會紀錄物件用來管理
/// </summary>
/// <param name="_gameObject"></param>
public void DontDestroyOnLoad(GameObject _gameObject)
{
indestructibleGameObjects.Add(_gameObject);
Object.DontDestroyOnLoad(_gameObject);
}
/// <summary>
/// 將 DontDestroyOnLoad 場景的遊戲物件移到當前場景,讓遊戲物件可以被清除。
/// </summary>
public void MoveGameObjects()
{
while (indestructibleGameObjects.Count > 0)
{
GameObject _gameObject = indestructibleGameObjects[0];
indestructibleGameObjects.RemoveAt(0);
SceneManager.MoveGameObjectToScene(_gameObject, SceneManager.GetActiveScene());
}
}
}
這裡有用到單例模式,Destroyer 本身也是被設計為 DontDestroyOnLoad,裡面的方法都有註解說明,我就不再贅述。
使用方式
新增一個空遊戲物件取名為 Destroyer,然後將添加 Destroyer 組件。
接著將 DontDestroyOnLoad 方法取代為 Destroyer.Instance.DontDestroyOnLoad()
,需注意如果在 Awake
方法呼叫 Destroyer.Instance.DontDestroyOnLoad()
可能會還沒找到 Destroyer 遊戲物件,因為這裡只用了最簡單的單例模式,Instance
沒有判斷是不是 null,只有單純回傳單例的實體而已。
private void Start()
{
Destroyer.Instance.DontDestroyOnLoad(gameObject);
}
結果
這是一個很陽春的組件,如果有其他功能需求,再自己新增上去就好,這裡主要想分享我在摧毀 DontDestroyOnLoad 遊戲物件時遇到的問題,和解決辦法。
一杯咖啡的力量,勝過千言萬語的感謝。
支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!