Unity Engine: Wie kann ich das Spiel stoppen (im Code)?
Hallo Community,
ich habe kürzlich einen Klon von Arkanoid in Unity nachgebaut. Dafür habe ich dieses Tutorial befolgt. Mit C# kenne ich mich recht gut aus, nur nicht mit Unity. Leider stellt das Tutorial zwar in Aussicht, dass man noch bestimmte Dinge tun könnte, zeigt aber einige der wirklich wichtigen Dinge davon nicht. Daher möchte ich gern folgende Dinge in Bezug auf Unity wissen:
- Wie stellt man fest, ob der Ball den unteren Bildschirmrand verlassen hat? Und wie wird das Spiel dann gestoppt?
- Was muss programmiert / eingestellt werden, um zu testen, ob noch Blöcke übrig sind?
- Auf welche Weise kann man ein weiteres Level aufrufen?
Zu 1: Hier habe ich bereits das Internet durchforstet. Laut dem, was ich gefunden habe, ist es das Beste, die Methode OnBecomeInvisible() aufzurufen und dort
Time.timeScale = 0;
zu setzen. Das habe ich in der Klasse für den Ball gemacht, aber leider konnte der Schläger immer noch bewegt werden. Was muss ich anders machen?
Zu 3: Ich habe bereits 2 weitere Level zusammengestellt. Jetzt weiß ich leider nicht, wie ich diese laden kann, sobald im vorherigen alle Blöcke zerstört wurden.
Danke schon mal für eure Hilfe.
1 Antwort
Hi!
Zu 1:
Genau, Du kannst für diesen Anwendungsfall wunderbar OnBecameInvisible benutzen. Du musst nur aufpassen, dass das eben für alle Richtungen gilt. Wenn Du es weiter einschränken willst, müsstest Du schon ob die y-Koordinate Deines GameObjects kleiner ist, als die sichtbare y-Koordinate Deiner Kamera. Alternativ, wenn's ganz einfach sein soll: Ein Trigger-Collider unterhalb der Map. Wenn der Ball dort ankommt, Deine Logik ausführen.
Das Spiel kannst Du mit timeScale = 0 anhalten. Ich hab mir das Tutorial angeschaut und so wie es entwickelt ist, sollte das funktionieren. Bist du sicher, dass es aufgerufen wird?
Und Achtung: Du hast OnBecomeInvisible geschrieben. Die Methode heißt aber OnBecameInvisible (Vergangenheitsform). Ich tippe daher, dass das Dein Problem sein könnte.
Zu 2:
Du könntest ein weiteres, leeres GameObject erzeugen, den BlockManager und dort folgendes Script drauf legen:
public class BlockManager : MonoBehavior {
// Block ist das Script aus dem Tutorial
private List<Block> _blocks = new List<Block>();
public void AddBlock(Block block) {
_blocks.Add(block);
}
public void RemoveBlock(Block block) {
_blocks.Remove(block);
if (_blocks.Count == 0) {
GameOver();
}
}
private void GameOver() {
// Spiel vorbei, neues Level laden, siehe Punkt 3
}
}
Dann erweiterst Du Script Block wie folgt:
public class Block : MonoBehavior {
// alles andere aus dem Tutorial...
private BlockManager _blockManager;
private void Awake() {
_blockManager = FindObjectOfType<BlockManager>();
_blockManager.AddBlock(this);
}
private void OnDestroy() {
_blockManager.RemoveBlock(this);
}
}
Der Ablauf ist wie folgt: Sobald das Spiel startet, ruft Unity automatisch die Methode Awake auf. Das registriert jeden Block bei einem Manager. OnDestroy wird aufgerufen, sobald das Objekt zerstört wird (durch Dein OnCollisionEnter2D) und meldet daraufhin den Block bei dem Manager wieder ab. Wurde der letzte Block entfernt, ist die Liste vom Manager leer und dann ruft er die Methode GameOver auf.
Zu 3:
Du kannst zum Start einfach eine neue Szene machen mit einem neuen Level. In GameOver kannst Du dann über SceneManager.LoadScene("NameDerScene") das nächste Level laden.
Als kleiner "Pro-Tipp": Bei so einem Spiel wie Arkanoid würde man nicht pro Level eine eigene Szene machen, sondern man würde die Information über die Blöcke in einer Datei ablegen und die Levels aus einer Datei laden. Aber irgendwo muss man ja anfangen. :-)
Du musst natürlich beim Wechseln des Levels Time.timeScale auf 1 zurück setzen. Solche Einstellungen sind szenenübergreifend. Das kannst du zum Beispiel direkt vor dem Aufruf von LoadScene machen. Oder du machst es in der Awake-Methode vom BlockManager.
Oder du schreibst dir noch ein Skript, was das Management von Level und Zeit übernimmt. :-)
Danke, es hat funktioniert. Habe mir jetzt eine weitere Klasse hinzugefügt, die zu einem weiteren leeren GameObject gehört. Hier gibt es eine öffentliche statische Methode, die den Teil mit dem GameOver regelt. Diese ruft wiederum eine private statische Methode auf, die das Level ändert, bevor es aufgerufen wird (über eine String-Variable). Die neue Klasse ruft in ihrer Awake-Methode dann DontDesrtoyOnLoad(this) auf.
Danke, das hat soweit alles funktioniert. Beim Stoppen einen Buchstaben verwechselt und schon funktioniert es nicht :)
Ich habe jetzt nur ein kleines Problem: Wenn das nächste Level geladen wurde, ist das Spiel automatisch gestoppt. Wie kann ich das Spiel wieder starten? Ich verwende im 2. Level die gleichen Scripte, wie im ersten. Wenn ich also ein weiteres Level hätte bzw. das zweite das Ende wäre, müsste ich in der GameOver-Methode das doch auch irgendwie feststellen können, oder? Oder muss ich für jedes Level einen eigenen BlockManager schreiben?
Danke auch für den Profi-Tipp. Fürs Erste werde ich eher mit den einzelnen Szenen arbeiten. Das Andere ist im Moment noch nicht innerhalb dessen, was ich über Unity weiß ;-) In WinForms und Konsolenanwendungen unter Windows mit .Net ist das alles irgendwie einfacher für mich xD