Wie kann ich alle DontDestroyOnLoad GameObjects erhalten?


7

Ich muss alle DontDestroyOnLoadGameObjects zerstören . Aber um dies zu tun, muss ich sie zuerst alle finden. Ich würde es vorziehen, dies zu automatisieren, anstatt jedes manuell referenzieren zu müssen.

DontDestroyOnLoadGameObjects scheinen alle in der gemeinsamen Szene zu sein "DontDestroyOnLoad". Also habe ich versucht, alle Root-GameObjects aus dieser Szene zu sammeln, aber es heißt, dass es sich um eine ungültige Szene handelt.

private void DestroyDontDestroyOnLoadGameObjects()
{
    var dontDestoyOnLoadScene = SceneManager.GetSceneByName("DontDestroyOnLoad");
    var dontDestroyOnLoadGameObjects = dontDestoyOnLoadScene.GetRootGameObjects();
    foreach (var dontdestroyGameObject in dontDestroyOnLoadGameObjects)
    {
        Destroy(gameObject);
    }
}

Geben Sie hier die Bildbeschreibung ein

Wie kann ich alle GameObjects zerstören, die sie DontDestroyOnLoadaufgerufen haben?

Antworten:


8

Hier ist eine freche kleine hackische Methode, die die nur im Editor funktioniert . Wir können die DontDestroyOnLoad-Szene nicht namentlich finden, aber jedes DontDestroyOnLoad'ed GameObject enthält einen Verweis darauf. Wenn wir also nur auf ein solches Objekt verweisen (oder ein solches Objekt erstellen), können wir zu allen gelangen:

public void DestroyAllDontDestroyOnLoadObjects() {

   var go = new GameObject("Sacrificial Lamb");
   DontDestroyOnLoad(go);

   foreach(var root in go.scene.GetRootGameObjects())
       Destroy(root);

}

Sie können vermeiden, jedes Mal ein Opferobjekt zu erstellen, wenn Sie diese Liste von Objekten bearbeiten müssen, indem Sie auf ein solches Objekt verweisen, von dem Sie wissen, dass es immer vorhanden ist (z. B. das Managerobjekt, auf dem sich dieses Skript befindet), oder indem Sie das ausführen Ritualopfer einmal zu Beginn des Laufs und Zwischenspeichern eines Verweises auf die Szene, der von da an verwendet werden soll (in meinen Tests bleibt es auch dann gültig, wenn alle Objekte zerstört und neue Objekte als DDOL gekennzeichnet wurden).

Beachten Sie, dass dieser Trick laut Dokumentation in einem erstellten Spiel nicht funktioniert :

Sie haben keinen Zugriff auf die DontDestroyOnLoad-Szene und sie ist zur Laufzeit nicht verfügbar.

Beim Versuch, auf diese Szene zuzugreifen, wird eine Ausnahme ausgelöst, die sich darüber beschwert, dass die Szene ungültig ist.


Wenn das rituelle Opfer Ihren Magen dreht (aus gutem Grund, würde ich sagen) oder wenn Sie dies zur Laufzeit in einem gebauten Spiel benötigen , wäre ein konventionellerer Ansatz die Einführung eines DontDestroyOnLoadManager wie folgt:

public static class DontDestroyOnLoadManager
{
    static List<GameObject> _ddolObjects = new List<GameObject>();

    public static void DontDestroyOnLoad(this GameObject go) {
       UnityEngine.Object.DontDestroyOnLoad(go);
       _ddolObjects.Add(go);
    }

    public static void DestroyAll() {
        foreach(var go in _ddolObjects)
            if(go != null)
                UnityEngine.Object.Destroy(go);

        _ddolObjects.Clear();
    }
}

Dann können Sie jede Instanz einer DontDestroyOnLoad(someObject)anderen Stelle in Ihrer Codebasis durch ersetzen someObject.DontDestroyOnLoad()(hier verwende ich eine Erweiterungsmethode, um sie kurz zu halten, aber Sie können sie auch explizit über Ihre Manager-Klasse aufrufen). Dies umschließt das native DontDestroyOnLoad und führt auch die erforderliche Buchhaltung durch, um alle diese Objekte später zu finden. Der Nachteil ist, wenn Sie zusätzliche Skripte und Plugins von Drittanbietern haben, die DontDestroyOnLoad aufrufen, müssen Sie diese ändern, um von diesem System verfolgt zu werden.


Klug! Vielen Dank! Funktioniert der erste nicht zur Laufzeit?
Evorlor

Nein, nicht im gebauten Spiel. Ich habe es getestet und es gibt Ausnahmen, wie in der Antwort angegeben. Wäre cool, wenn es so wäre, aber ehrlich gesagt, wie hackig es ist, wundert es mich nicht, dass es nicht so ist. ;)
DMGregory

Ah, ich habe die Bearbeitung nicht gesehen. Nochmals vielen Dank für eine weitere tolle Antwort!
Evorlor

Ich denke es ist rückwärts. Sie können Szenen nur zur Laufzeit gegenseitig bearbeiten. Von Ihrer URL: Cross-Scene references are not supported, and are prevented in Edit mode. In Play mode they are allowed, because Scenes cannot be saved.Ich glaube, der Abschnitt, auf den Sie sich bezogen haben, ist für Unity v5.3 und früher. Und es funktioniert zur Laufzeit für mich. Da Sie DontDestroyOnLoad GameObjects nicht haben können, bevor Sie auf "Play" klicken, sollte dies im Editor kein Problem sein.
Evorlor

1
Eine mögliche Anwendung besteht darin, die Hacky-Version in die Manager-Version innerhalb einer #IF UNITY_EDITORDirektive einzufügen . Dort kann es die Objekte in der DontDestroyOnLoad-Szene mit unserer Buchhaltungsliste vergleichen und Warnungen auslösen, wenn Sie den Wrapper irgendwo nicht verwendet haben und ein streunendes DontDestroyOnLoad-Objekt außerhalb unserer Liste erstellt wurde.
DMGregory
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.