Zwischen Szenen beibehalten
Teil des Abschnitts Echte Spiele entwickeln der Unity-Journey von Coddy. Lektion 20 von 56.
Beim Laden einer Szene wird jedes Objekt der alten Szene zerstört, aber manche Dinge müssen das ganze Spiel über bestehen bleiben, etwa die Münzen, die ein Spieler von Level zu Level mitnimmt. DontDestroyOnLoad(gameObject) verschiebt ein Objekt aus seiner Szene in eine eigene Szene namens DontDestroyOnLoad, die in der Hierarchy während Play angezeigt wird und von Ladevorgängen nicht berührt wird. Das funktioniert nur mit einem Stammobjekt: Bei einem untergeordneten Objekt gibt Unity eine Warnung aus und behält nichts bei. Die untergeordneten Objekte des beibehaltenen Objekts kommen mit, aber Objekte, auf die es lediglich verweist, nicht: Nach dem Laden enthält ein Feld, das auf ein Objekt der alten Szene verwies, ein zerstörtes Objekt, das mit null gleich ist.
public class GameSession : MonoBehaviour
{
public static GameSession Instance;
public int coins;
void Awake()
{
if (Instance != null)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
}Diese GameSession befindet sich in der Menu-Szene. Beim Spielen geht es von Menu zu Level1 und dann zurück zu Menu, und Menu erstellt alle seine Objekte erneut, einschließlich einer neuen GameSession, während die beibehaltene noch vorhanden ist. Ohne die Prüfung in Awake gäbe es zwei, und die neue würde Instance mit 0 Münzen überschreiben. Mit der Prüfung stellt die neue fest, dass Instance bereits gesetzt ist, zerstört sich selbst und beendet die Ausführung, und die Session, die die Level durchlaufen hat, bleibt erhalten.
Das return ist wichtig, weil Destroy bis zum Ende des Frames wartet. Ohne es würde der Rest von Awake für die neue Instanz weiterhin ausgeführt: Instance = this; würde jedes Skript auf ein Objekt verweisen lassen, das kurz davor ist, zerstört zu werden.
Aufgabe
EinfachEine Speedrun-Uhr. Das RunClock-Objekt in Level1 zählt die Sekunden des gesamten Durchlaufs und protokolliert jedes Mal eine Zwischenzeit, wenn ein Level abgeschlossen wird. Das goldene Goal von Level1 lädt Level2, dessen Goal wiederum Level1 lädt, und jedes Goal ruft zuerst RunClock.Instance.Split() auf. Jedes Level hat ein eigenes HUD mit einem ClockText; im Inspector wird dem RunClock das Objekt aus Level1 zugewiesen. Mit den Pfeiltasten bewegst du den Player. Ändere RunClock.cs, sodass:
- die Uhr bei jedem Szenenwechsel weiterläuft, ohne von vorn anzufangen;
- die Zeit immer im
ClockTextdes geöffneten Levels alsTime: 12.3angezeigt wird; - bei der Rückkehr zu Level1, das einen eigenen RunClock enthält, trotzdem nur eine Uhr übrig bleibt – die, die bereits gelaufen ist – und
RunClock.Instanceauf diese verweist.
Drücke Spielen, gehe zu Level2 und zurück und schließe Level1 erneut ab. Klicke dann auf Überprüfen.
Probier es selbst
using UnityEngine;
using TMPro;
public class RunClock : MonoBehaviour
{
public static RunClock Instance;
public TMP_Text clockText;
private float seconds;
void Awake()
{
Instance = this;
}
void Update()
{
seconds += Time.deltaTime;
clockText.text = "Time: " + seconds.ToString("0.0");
}
public void Split()
{
Debug.Log("Split: " + seconds.ToString("0.0"));
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Echte Spiele entwickeln
1Text auf dem Bildschirm
Canvas und TextPunktestand anzeigenZahlen formatierenEin Countdown-TimerRückblick: Tachometer4Szenen und Level
Eine Szene ladenDas Level neu startenNächstes LevelZwischen Szenen beibehaltenRückblick: Levelauswahl10Projekt: 3D-Plattformer
Der ParcoursBewegliche Plattformen2Buttons und Bildschirme
Buttons und onClickLambdasVerknüpfungen im InspectorPanels ein- und ausblendenGesundheitsbalkenRückblick: Upgrade-Shop5Speichern mit PlayerPrefs
Eine Zahl speichernMit einem Standardwert ladenHöchstpunktzahlEinstellungen speichernRückblick: Münzen auf der Bank