Zwischen Szenen beibehalten
Teil des Abschnitts Echte Spiele entwickeln der Unity-Journey von Coddy. Lektion 20 von 60.
Beim Laden einer Szene wird jedes Objekt der alten 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 in der Hierarchy bei „Spielen“, die vom Laden nie berührt wird. Das funktioniert nur mit einem Stammobjekt: Bei einem untergeordneten Objekt gibt Unity eine Warnung aus und behält nichts. 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 verwiesen hat, ein zerstörtes Objekt, das mit null übereinstimmt.
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. „Spielen“ führt von Menu zu Level1 und dann zurück zu Menu. Dabei erstellt Menu 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 neu hinzugekommene 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. Die Session, die die Level durchlaufen hat, bleibt bestehen.
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 darauf zerstört wird.
Aufgabe
EinfachLass eine einzige Laufzeituhr bei jedem Szenenladen weiterlaufen.
- Rufe in
Awake(), fallsInstance != null,Destroy(gameObject);undreturn;auf. Andernfalls setzeInstanceund rufeDontDestroyOnLoad(gameObject);auf. - Beim Laden wird der Text der alten Ebene zerstört. Setze daher in
Update()vor der Textzeile, wennclockText == null,clockText = GameObject.Find("ClockText").GetComponent<TMP_Text>();.
Drücke „Spielen“, gehe zu Level2 und zurück: Eine Uhr zählt weiter. Klicke dann auf „Prü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"));
}
}
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: Levelauswahl2Buttons 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Übe selbstständig: Unity-Playground