Hier erst mal ein ausführliches Video-Tutorial, das folgende Fragen beantwortet:

  1. Wie wechseln wir in Greenfoot die Welt (bzw. ein Level?
  2. Wie können wir den Leveln unterschiedliche Eigenschaften geben?
  3. Wie schaffen wir es, dass die Spielfigur(en) in die einzelnen Level kommt, ohne ihre Attributwerte (z.B. Punktestand) zu verlieren?

BEVOR ich das Video gemacht habe, habe ich diese Erläuterungen unten geschrieben. Wer es sich also lieber durchliest, voila:

Zuerst erstellen wir eine Welt mit mehreren Levels, Beispiel:

greenfoot3-welt-mehrer-levels

Pro-Tipp: Es empfiehlt sich, die Levels (im Beispiel: Level1, Level2) als Unterklassen zu einer Weltklasse (im Beispiel:MyWorld) anzulegen. Evtl. will man in allen Leveln die gleichen Methoden verwenden (z.B. Musikloop abspielen, via Konstruktor Knöpfe oder Statusanzeigen auf die Welt setzen etc.). Diese muss man dann nicht für jeden Level wiederholt programmieren/einfügen, sondern kann sie in der Oberklasse (MyWorld) programmieren, dann sind sie in allen Unterklassen bekannt, als hätte man sie dort programmiert (mehr dazu: Greenfoot 3 Folge 42: Grundlagen der Vererbung). Achtung! Methoden der Unterklasse "überschreiben" Methoden der Oberklasse. Wenn Level1 eine act()-Methode enthält, wird die act()-Methode der MyWorld nicht mehr ausgeführt!

Startlevel festlegen

Rechte Maustaste auf den gewünschten Level -> new Level1() (also wie bekannt ein neues Objekt anlegen); Greenfoot 3 "merkt" sich das und startet das Programm fortan immer mit diesem Level.

Level während des Spiels wechseln

Der Befehl hierfür lautet Greenfoot.setWorld(...). Schreiben Sie z.B. in die act()-Methode einer Spielfigur:

if(Greenfoot.isKeyDown("L"))
    Greenfoot.setWorld( new Level2())

Problem: Attributwerte (z.B. Punktestand) gehen durch Levelwechsel verloren

(Wie Sie Punktestände, Anzahl von Kollisionen, eingesammelte Gegenstände etc. festhalten, erfahren Sie hier: Zähler für Punkte, Kollisionen etc. in Greenfoot 3 bauen)

Der oben dargestellte Levelwechsel funktioniert gut, hat aber einen wesentlichen Nachteil: Durch das Neuerzeugen der Welt (mit z.B. new Level2() ) werden alle Attributwerte etc. zurückgesetzt. Es werden neue Spielfiguren erzeugt, deren Attribute wieder neu deklariert werden; damit wäre ein in der Spielfigur gespeicherter Punktestand wieder bei 0.

Hier gibt es mehrere Lösungsansätze, wobei die meisten nicht ganz unkompliziert sind. Man kann z.B. ein eigenes Counter-Objekt erzeugen. Aufwändiger (aber sehr professionell ist die Super Level Support Class von danpost - allerdings in Java, man müsste das erst noch in Stride-Code umbauen.

In solchen Fällen hat man eine aufwändige Modellierung, da Weltklasse(n), Spielfigur(en) und eventuelle Hilfsklassen miteinander interagieren müssen. Im Folgenden drei Lösungen, die einigermaßen einfach umzusetzen sind.

Möglichkeit 1 - Einfachste Lösung: Statische Variablen für Punktestände etc. benutzen

Die Verwendung von statischen Variablen ist die einfachste (wenn auch etwas dreckige) Lösung: Sie speichern in Ihrer Spielfigur Zählerstände usw., setzen die Variable aber auf statisch (Rechtsklick auf das Attribut -> Make static):

greenfoot3-statischer-zaehler

Dann wird der Wert in der Klasse gespeichert (und wenn Sie während des Spiels neue Spielfiguren erzeugen, haben alle für zaehler den gleichen Wert, Vorsicht!). So können Sie Objekte der Klasse Spielfigur löschen, neu anlegen usw., der Attributwert bleibt immer erhalten - sehr praktisch.

Nachteil dieser Methode: Der Wert bleibt auch erhalten, wenn Sie Ihr Szenario neu starten - um Ihren Wert wirklich neu zu initialisieren, müssen Sie Greenfoot ganz beenden und neu starten (oder den Wert explizit auf 0 setzen, wenn das Spiel vorbei ist, damit er bei Neustart wirklich 0 ist).

Möglichkeit 2 - Spielfigur(en) als Parameter an neue Level übergeben

(Ein Szenario zu den folgenden Ausführungen können Sie hier herunterladen: levelchange.zip (Greenfoot 3 / Stride-Szenario))

Das Problem liegt ja darin, dass bei der Erzeugung eines neuen Levels mit z.B. new Level2() alle Objekte unserer Spielwelt ebenfalls neu erzeugt werden und dann die bisherigen Werte nicht mehr zur Verfügung stehen. Die Idee liegt nun darin, dem Konstruktor eines jeden Levels die bestehende Objektreferenz (also das vorhandene Objekt) zu übergeben; dieses Objekt behält dann alle seine Werte wie Punktestände etc.

Zuerst bekommt die Spielfigur ein Attribut, in dem Punktestände, Kollisionen o.ä. gespeichert sind:

private int zaehler = 0

Der Konstruktor der Level-Oberklasse erhält ein Spielfigur-Objekt (bzw. genauer: die Referenz auf ein Objekt der Klasse Spielfigur) als Parameter und setzt dieses Objekt auf die Welt:

public MyWorld(Spielfigur s)
super(600, 400, 1)
this.addObject(s, 200, 200)

Im Konstruktor eines jeden Levels übergeben wir nun als allererstes mit einem super()-Aufruf unser Spielfiguren-Objekt an die Oberklasse. Wenn Sie verstehen möchten, wie das funktioniert, schauen Sie hier: Greenfoot 3 Folge 43: Vererbung mit super()-Aufruf.

In Level1 - also zu Beginn des Spiels - ist noch keine Spielfigur vorhanden. Wir geben also eine neue Spielfigur an den Konstruktor der MyWorld-Klasse, die diese Spielfigur dann zur Welt hinzufügt:

public Level1()
super( new Spielfigur() )

Wenn der Level wechselt, übergeben wir die vorhandene Spielfigur an den nächsten Level. So könnte in der Klasse Spielfigur stehen:

if(Greenfoot.isKeyDown("L"))
// oder: if(this.anzahlGoldstuecke == 100)
Greenfoot.setWorld( new Level2(this) )

this ist in diesem Falle die "Selbstreferenz" des Objektes Spielfigur; die Spielfigur gibt sich also quasi selbst als Parameter an den Level2. Level2 bekommt also die Spielfigur als Parameter und reicht sie an den Konstruktor der Oberklasse MyWorld durch:

public Level2(Spielfigur s)
super(s)

Entsprechend könnten wir natürlich auch die aktuelle Position der Spielfigur durchgeben. Dann stünde in der MyWorld-Klasse z.B.

public MyWorld(Spielfigur s, int xPos, int yPos)
super(600, 400, 1)
this.addObject(s, xPos, yPos)

und in der Spielfigur

if(Greenfoot.isKeyDown("L"))
// oder: if(this.anzahlGoldstuecke == 100)
Greenfoot.setWorld( new Level2(this, this.getX(), this.getY()) )

Zusammengefasst sieht das Ganze so aus:

greenfoot3-vererbung

Möglichkeit 3 - Punktestand in Weltklasse speichern und bei Levelwechsel als Parameter an die Level übergeben

Wir speichern den Punktestand in unserer Weltklasse als Attribut. Wichtig ist, dass wir das Attribut auf protected setzen, damit die Unterklassen es verwenden können. Außerdem schreiben wir Getter und Setter für den Punktestand (Erklärung: Greenfoot 3 Folge 40: Getter und Setter programmieren). Getter und Setter brauchen wir, um von der Klasse Spielfigur aus auf das Attribut Punktestand zugreifen zu können.

greenfoot3-weltklasse-mit-getter-setter

DIe Level erhalten nun einen Konstruktor mit Parameter, der den aktuellen Punktestand zuweist. Das Attribut punktestand ist den Level-Unterklassen bekannt, da es in der Oberklasse (hier: MyWorld) als protected deklariert wurde:

greenfoot3-level-mit-konstruktorparameter

Sobald nun der Level gewechselt wird, können wir an den Level den aktuellen Punktestand übergeben, zum Beispiel in der Klasse Spielfigur so:

public void act()
    var MyWorld weltOberklasse = (MyWorld)this.getWorld()
    weltOberklasse.setPunktestand(weltOberklasse.getPunktestand() + 1)
    this.getWorld().showText("Punkte: " + weltOberklasse.getPunktestand(), 200, 100)
    if(Greenfoot.isKeyDown("L"))
        Greenfoot.setWorld( new Level2(weltOberklasse.getPunktestand() ) )

Erklärung: Wir speichern die Welt-Oberklasse in einer Variablen weltOberklasse. Damit wir die Attribute und Methoden, die wir in der MyWorld-Klasse definiert haben, benutzen können, müssen wir das World-Objekt, das uns mit this.getWorld() zurückgegeben wird, durch (MyWorld) zu einem MyWorld-Objekt umbauen.

Nun können wir auf unsere Zugriffsmethoden (Getter/Setter, siehe oben) zugreifen und den Punktestand verändern oder den Punktestand verwenden. Wesentlich daran ist, dass wir nun den Punktestand beim Erzeugen eines neuen Levels an diesen Level übergeben können. Damit kennt im Beispiel Level2 den aktuellen Punktestand, der Punktestand bleibt beim Levelwechsel erhalten.

Level überprüfen

Wenn Sie gerne wissen möchten, in welchem Level Sie sich befinden, können Sie schreiben:

if(this.getWorld() instanceof Level1)    System.out.println("Sie sind in Level 1")

Wie das in Stride-Szenarien geht, weiß ich im Moment nicht (in Java-Szenarien tippen Sie es einfach ein wie oben dargestellt). Falls es jemand weiß, freue ich mich über eine kurze Mail über das Kontaktformular (ganz unten auf der Seite).