K (Reaktion auf Kollisionen)
K (Reaktion auf Kollisionen)
 
(12 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 99: Zeile 99:
 
In den einzelnen Fällen kannst du geerbte Methoden, eigene Methoden oder Methoden von Referenzen aufrufen.
 
In den einzelnen Fällen kannst du geerbte Methoden, eigene Methoden oder Methoden von Referenzen aufrufen.
  
Der Folgende Code in der Klasse <code>Haus</code> steuert den Tag- und Nacht-Modus über die Tastatur:
+
Der folgende Code in der Klasse <code>Haus</code> steuert den Tag- und Nacht-Modus über die Tastatur:
 +
 
 +
[[Datei:Haus v2.gif|mini|Tag- und Nacht-Modus werden durch Tastatur-Eingaben gesteuert]]
  
 
<source lang="java">
 
<source lang="java">
Zeile 127: Zeile 129:
  
 
Die Klasse <code>SPEIL</code> verfügt neben der Methode zum automatischen Reagieren auf Tastatur-Ereignisse über eine Methode <code>bildAktualisierungReagieren(double zeit)</code> die jedesmal automatisch aufgerufen wird sobald ein neues Bild gezeichnet wird. Automatisch wird auch die Zeit in Sekunden mitgeliefert, die seit der letzten Bildaktualisierung vergangen ist. (Diese Zeit liegt etwa im Bereich 1/60 Sekunde, da die Engine etwa 60 Bilder pro Sekunde erzeugt. Für die folgende Anwendung werten wir diesen Parameter aber nicht aus.) Durch überschreiben dieser Methode kannst du am sinnvollsten auf Kollisionen reagieren.
 
Die Klasse <code>SPEIL</code> verfügt neben der Methode zum automatischen Reagieren auf Tastatur-Ereignisse über eine Methode <code>bildAktualisierungReagieren(double zeit)</code> die jedesmal automatisch aufgerufen wird sobald ein neues Bild gezeichnet wird. Automatisch wird auch die Zeit in Sekunden mitgeliefert, die seit der letzten Bildaktualisierung vergangen ist. (Diese Zeit liegt etwa im Bereich 1/60 Sekunde, da die Engine etwa 60 Bilder pro Sekunde erzeugt. Für die folgende Anwendung werten wir diesen Parameter aber nicht aus.) Durch überschreiben dieser Methode kannst du am sinnvollsten auf Kollisionen reagieren.
 +
 +
[[Datei:Kollision v1.gif|mini|Ergebnis im Grafikfenster]]
 +
 +
<source lang="java">
 +
public class MeinSpiel
 +
extends SPIEL
 +
{
 +
  private KREIS ball;
 +
  private RECHTECK wand;
 +
 
 +
  public MeinSpiel()
 +
  {
 +
      this.ball = new KREIS(2);
 +
      this.ball.setzeMittelpunkt(-10,0);
 +
      this.ball.setzeGeschwindigkeit(4,0);
 +
      this.wand = new RECHTECK(0.5,20);
 +
      this.wand.setzeMittelpunkt(10,0);
 +
  }
 +
 
 +
  @Override
 +
  public void bildAktualisierungReagieren(double zeit)
 +
  {
 +
      if ( this.ball.beruehrt(this.wand) )
 +
    {
 +
        this.ball.setzeFarbe("gelb");
 +
        this.ball.setzeGeschwindigkeit(0,0);
 +
    }
 +
  }
 +
}
 +
</source>
 +
 +
Der Ball läuft auf die Wand zu und wenn das erste Bild gezeichnet wird, bei dem der Ball die Wand berührt, bleibt der Ball stehen und wird gelb.
  
 
=== Ticker für wiederkehrende Aufgaben ===
 
=== Ticker für wiederkehrende Aufgaben ===
  
 +
Die Klasse <code>SPIEL</code> bietet noch weitere Mechanismen an. Einer davon ist das Ticker-System. Die Methode <code>tick()</code> wird automatisch in regelmäßigen Zeitabständen immer wieder aufgerufen, sobald das Tickersystem gestartet ist. Zum starten und stoppen des Ticker-Systems gibt es die Methoden <code>starteTickerNeu(double sekunden)</code> sowie <code>stoppeTicker()</code>. Mit Hilfe des Ticker-Systems können regelmäßig wiederkehrende Aufgaben automatisch erledigt werden.
 +
 +
Im folgenden erstellst du einen Sekunden-Zähler, der bei 10 beginnt und dann im Sekundentakt herunter gezählt wird.
 +
 +
[[Datei:Timer v1.gif|mini|Der Timer in Aktion]]
 +
 +
<source lang="java">
 +
public class MeinSpiel
 +
extends SPIEL
 +
{
 +
  private int zaehler;
 +
  private TEXT anzeige;
 +
 
 +
  public MeinSpiel()
 +
  {
 +
      this.zaehler = 10;
 +
      this.anzeige = new TEXT(0, 0, 10, this.zaehler);
 +
      super.starteTickerNeu(1);
 +
  }
 +
 
 +
  @Override
 +
  public void tick()
 +
  {
 +
      this.zaehler = this.zaehler - 1;
 +
      this.anzeige.setzeInhalt(""+this.zaehler);
 +
      this.anzeige.setzeMittelpunkt(0,0);
 +
      if ( this.zaehler == 0 )
 +
      {
 +
        super.stoppeTicker();
 +
      }
 +
  }
 +
}
 +
</source>
 +
 +
Zuerst wird eine ganzzahlige Zählvariable und ein Textfeld deklariert.
 +
 +
Im Konstruktor bekommt der Zähler den Startwert 10 und wird im Textfeld an den Koordinaten (0|0) mit Größe 10 angezeigt. zuletzt wird das Ticker-System gestartet mit einem Intervall von 1 Sekunde.
 +
 +
Im Rumpf der überschriebenen Methode <code>tick()</code> wird bei jedem Tick erst der Zähler um Eins herab gesetzt und anschließend angezeigt. das Konstrukt <code>""+this.zaehler()</code> sorgt dafür, dass wirklich die ganze Zahl angezeigt wird und nicht eine Kommazahl. Da sich z.B. von 10 nach 9 die Breite des Textfeldes ändert wird es neu zentriert. Wenn der Zähler bei 0 angekommen ist, wird das Ticker-System wieder beendet.
  
 
=== Anregungen zu Experimentieren ===
 
=== Anregungen zu Experimentieren ===
  
* Steuere die Ampelphasen des Ampel-Projekts mit der Tastatur.
+
* Steuere die Ampelphasen des Ampel-Projekts mit der Tastatur.  
 +
* Nutze das Ticker-System um die Ampel automatisch schalten zu lassen.
 +
 
 +
[[Datei:Pong v2.gif|mini|Das Pong-Spiel in Aktion]]
 +
 
 
* Steuere die Schläger des Pong-Projekts über die Tastatur. Informiere dich über die auch noch vorhandene Methode tasteLosgelassenReagieren(...). Mit ihr in Zusammenarbeit mit tasteReagieren(...) kannst du erreichen, dass bei drücken einer Taste die Geschwindigkeit des Schlägers so gesetzt wird dass dieser sich ab jetzt bewegt. Beim loslassen der Taste wird die Geschwindigkeit des Schlägers auf Null gesetzt und er bleibt stehen.
 
* Steuere die Schläger des Pong-Projekts über die Tastatur. Informiere dich über die auch noch vorhandene Methode tasteLosgelassenReagieren(...). Mit ihr in Zusammenarbeit mit tasteReagieren(...) kannst du erreichen, dass bei drücken einer Taste die Geschwindigkeit des Schlägers so gesetzt wird dass dieser sich ab jetzt bewegt. Beim loslassen der Taste wird die Geschwindigkeit des Schlägers auf Null gesetzt und er bleibt stehen.
 +
* Mache im Pong-Projekt den Ball dynamisch. Den Rand oben sowie den Rand unten machst du statisch. Die beiden Schläger machst du kinematisch. Im Konstruktor deiner Unterklasse von SPIEL setzt du die Schwerkraft auf Null und die Geschwindigkeit des Balls auf einen geeigneten Wert. Jetzt kannst du bereits spielen! Kollisionen des Balls mit dem linken bzw. rechten Rand führen zu Punktgewinn des entsprechenden Spielers und der Ball wird wieder in die Mittel des Spielfelds gesetzt. Ändere das Spielverhalten deinen Bedürfnissen entsprechend ab: Lasse z.B. den Ball mithilfe des Ticker-Systems alle 10 Sekunden schneller werden ...
 +
 +
  
  
  
 
{{4.xTutorialFooter|
 
{{4.xTutorialFooter|
[[v4.x/_xxx_|_yyy_]]
+
[[v4.x/Superklasse_EduActor|Die Superklasse EduActor]]
 
}}
 
}}

Aktuelle Version vom 9. Juni 2023, 00:28 Uhr


Dies ist ein Tutorial für die Edu-Variante der Engine Alpha 4.x. Eine Übersicht aller Edu-Tutorials siehst du hier.

Inhalt

In diesem Tutorial:

  • Lernst du das Verhalten von geerbten Methoden zu verändern:
    • Du reagierst auf Tastatur-Ereignisse
    • Du startest einen Ticker, der fortwährend Aufgaben automatisch erledigt
    • Du verstehst wie Bewegungen dargestellt werden und reagierst dadurch exakt auf Kollisionen

Überschreiben von Methoden

Bisher hast du entweder vorhandene Methoden aufgerufen oder du hast in deinen Klassen selbst neue Methoden erstellt. Manchmal ist es nützlich, geerbte Methoden abzuändern. Manchmal möchtest du dem bisherigen Verhalten einfach nur etwas hinzufügen. Manchmal erbst du einen Mechanismus, z.B. Reaktion auf Maus oder Tastatur und nun willst du selbst festlegen, was z.B. bei deinem Mausklick passieren soll. In beiden Fällen überschreibt man die geerbte Methode, das heißt man erstellt eine Methode, die man genau in diesem Wortlaut und mit dieser Parameterliste schon geerbt hat.

public class MeineKlasse
extends Oberklasse
{
   ...
   @Override
   public nameDerGeerbtenMethode( ... Paramterliste ... )
   {
      // jetzt passiert was ich will
   }
}

Reaktion auf Tastatur-Ereignisse

Klasse SPIEL

In der Edu-Engine gibt es eine Klasse SPIEL die dir einige Mechanismen anbietet, wenn du von ihr erbst. Einer dieser Mechanismen ist die Fähigkeit, automatisch auf Tastatur-Eingaben reagieren zu können.

Vorübung

Erstelle in deiner Entwicklungsumgebung interaktiv ein Objekt der Klasse Spiel. Nutze zunächst den Konstruktor ohne Parameter. Drücke nun auf deiner Computertastatur eine beliebige Taste. Was beobachtest du?

Konsolenausgabe

Jedes mal wenn du eine Taste drückst erscheint auf der Konsole die Ausgabe "Taste ... wurde gedrückt". Die Klasse Spiel verfügt also über einen Mechanismus um automatisch auf Tastatur-Ereignisse zu reagieren. Wie Geht das?

Die Klasse SPIEL verfügt über die Methode public void tasteReagieren(int tastenCode), die jedesmal automatisch aufgerufen wird, wenn ein Tastatur-Ereignis eintritt. Der Methode wird außerdem automatisch eine Zahl (der Tasten-Code) übergeben. Jede Taste hat eine andere Nummer und so kannst du anhand der Nummer wissen, welche Taste es war.

public class MeinSpiel
extends SPIEL
{
   @Override
   public void tasteReagieren(int tastenCode)
   {
      if ( tastenCode == 38 )
      {
         // Das geschieht bei Taste "Pfeil rauf"
      }
      else if ( tastenCode == ... )
      {
         ...
      }
   }
}

Du musst eine Unterklasse von SPIEL erstellen und darin die geerbte Methode public void tasteReagieren(int tastenCode) überschreiben. Standardmäßig gibt sie auf der Konsole den bekannten Text aus. Du schreibst nun in ihrem Rumpf eine Fallunterscheidung anhand der übergebenen Nummer. So kannst du auf jede beliebige Taste individuell reagieren.

Der Tasten-Code

Klassenkarte TASTE

Nun ist es mühsam, sich für jede benötigte Taste die Nummer zu merken. Deshalb gibt es die Klasse TASTE, die via Punktnotation sprechende Konstanten für jede Taste zur Verfügung stellt: TASTE.A ... TASTE.Z , TASTE._0 ... TASTE._9 , TASTE.RAUF, TASTE.RECHTS, TASTE.RUNTER, TASTE.LINKS, TASTE.LEER, TASTE.ENTER, ...

Du kannst weitere Konstanten in der Klasendokumentation nachlesen.

public class MeinSpiel
extends SPIEL
{
   @Override
   public void tasteReagieren(int tastenCode)
   {
      if ( tastenCode == TASTE.A )
      {
         // Das geschieht bei Taste A
      }
      else if ( tastenCode == TASTE.B)
      {
         ...
      }
   }
}

Der Code ist nun leichter lesbar!

In den einzelnen Fällen kannst du geerbte Methoden, eigene Methoden oder Methoden von Referenzen aufrufen.

Der folgende Code in der Klasse Haus steuert den Tag- und Nacht-Modus über die Tastatur:

Tag- und Nacht-Modus werden durch Tastatur-Eingaben gesteuert
public class Haus
extends SPIEL
{
   ...
   @Override
   public void tasteReagieren(int tastenCode)
   {
      if ( tastenCode == TASTE.N )
      {
         this.nacht();
      }
      else if ( tstenCode == TASTE.N )
      {
         this.tag();
      }
   }

Reaktion auf Kollisionen

Um auf andere Objekte zu reagieren stellt die Klasse EduActor für all ihre Unterklassen die Methode public boolean beruehrt(EduActor anderer) zur Verfügung. Diese Methode müsste während eines Spiels allerdings permanent aufgerufen werden, da sich die Spielfiguren ja andauernd bewegen. Im Idealfall müsste man dies bei jeder auch nur kleinsten Bewegung irgendeiner Spielfigur prüfen. Wie geht das?

Dazu musst du erst verstehen, wie die Grafiken und Animationen auf deinem Bildschirm entstehen. Der Eindruck einer Bewegung am 2D-Bildschirm entsteht durch eine sehr schnelle Folge von Einzelbildern zwischen denen sich nur kleinste Änderungen ergeben haben. In der Regel werden dir heute 30-60 solcher Bilder pro Sekunde untergejubelt, wenn du eine flüssige Bewegung wahrnehmen sollst.

Die Klasse SPEIL verfügt neben der Methode zum automatischen Reagieren auf Tastatur-Ereignisse über eine Methode bildAktualisierungReagieren(double zeit) die jedesmal automatisch aufgerufen wird sobald ein neues Bild gezeichnet wird. Automatisch wird auch die Zeit in Sekunden mitgeliefert, die seit der letzten Bildaktualisierung vergangen ist. (Diese Zeit liegt etwa im Bereich 1/60 Sekunde, da die Engine etwa 60 Bilder pro Sekunde erzeugt. Für die folgende Anwendung werten wir diesen Parameter aber nicht aus.) Durch überschreiben dieser Methode kannst du am sinnvollsten auf Kollisionen reagieren.

Ergebnis im Grafikfenster
public class MeinSpiel
extends SPIEL
{
   private KREIS ball;
   private RECHTECK wand;
   
   public MeinSpiel()
   {
      this.ball = new KREIS(2);
      this.ball.setzeMittelpunkt(-10,0);
      this.ball.setzeGeschwindigkeit(4,0);
      this.wand = new RECHTECK(0.5,20);
      this.wand.setzeMittelpunkt(10,0);
   }
   
   @Override
   public void bildAktualisierungReagieren(double zeit)
   {
      if ( this.ball.beruehrt(this.wand) )
     {
        this.ball.setzeFarbe("gelb");
        this.ball.setzeGeschwindigkeit(0,0);
     }
   }
}

Der Ball läuft auf die Wand zu und wenn das erste Bild gezeichnet wird, bei dem der Ball die Wand berührt, bleibt der Ball stehen und wird gelb.

Ticker für wiederkehrende Aufgaben

Die Klasse SPIEL bietet noch weitere Mechanismen an. Einer davon ist das Ticker-System. Die Methode tick() wird automatisch in regelmäßigen Zeitabständen immer wieder aufgerufen, sobald das Tickersystem gestartet ist. Zum starten und stoppen des Ticker-Systems gibt es die Methoden starteTickerNeu(double sekunden) sowie stoppeTicker(). Mit Hilfe des Ticker-Systems können regelmäßig wiederkehrende Aufgaben automatisch erledigt werden.

Im folgenden erstellst du einen Sekunden-Zähler, der bei 10 beginnt und dann im Sekundentakt herunter gezählt wird.

Der Timer in Aktion
public class MeinSpiel
extends SPIEL
{
   private int zaehler;
   private TEXT anzeige;
   
   public MeinSpiel()
   {
      this.zaehler = 10;
      this.anzeige = new TEXT(0, 0, 10, this.zaehler);
      super.starteTickerNeu(1);
   }
   
   @Override
   public void tick()
   {
      this.zaehler = this.zaehler - 1;
      this.anzeige.setzeInhalt(""+this.zaehler);
      this.anzeige.setzeMittelpunkt(0,0);
      if ( this.zaehler == 0 )
      {
         super.stoppeTicker();
      }
   }
}

Zuerst wird eine ganzzahlige Zählvariable und ein Textfeld deklariert.

Im Konstruktor bekommt der Zähler den Startwert 10 und wird im Textfeld an den Koordinaten (0|0) mit Größe 10 angezeigt. zuletzt wird das Ticker-System gestartet mit einem Intervall von 1 Sekunde.

Im Rumpf der überschriebenen Methode tick() wird bei jedem Tick erst der Zähler um Eins herab gesetzt und anschließend angezeigt. das Konstrukt ""+this.zaehler() sorgt dafür, dass wirklich die ganze Zahl angezeigt wird und nicht eine Kommazahl. Da sich z.B. von 10 nach 9 die Breite des Textfeldes ändert wird es neu zentriert. Wenn der Zähler bei 0 angekommen ist, wird das Ticker-System wieder beendet.

Anregungen zu Experimentieren

  • Steuere die Ampelphasen des Ampel-Projekts mit der Tastatur.
  • Nutze das Ticker-System um die Ampel automatisch schalten zu lassen.
Das Pong-Spiel in Aktion
  • Steuere die Schläger des Pong-Projekts über die Tastatur. Informiere dich über die auch noch vorhandene Methode tasteLosgelassenReagieren(...). Mit ihr in Zusammenarbeit mit tasteReagieren(...) kannst du erreichen, dass bei drücken einer Taste die Geschwindigkeit des Schlägers so gesetzt wird dass dieser sich ab jetzt bewegt. Beim loslassen der Taste wird die Geschwindigkeit des Schlägers auf Null gesetzt und er bleibt stehen.
  • Mache im Pong-Projekt den Ball dynamisch. Den Rand oben sowie den Rand unten machst du statisch. Die beiden Schläger machst du kinematisch. Im Konstruktor deiner Unterklasse von SPIEL setzt du die Schwerkraft auf Null und die Geschwindigkeit des Balls auf einen geeigneten Wert. Jetzt kannst du bereits spielen! Kollisionen des Balls mit dem linken bzw. rechten Rand führen zu Punktgewinn des entsprechenden Spielers und der Ball wird wieder in die Mittel des Spielfelds gesetzt. Ändere das Spielverhalten deinen Bedürfnissen entsprechend ab: Lasse z.B. den Ball mithilfe des Ticker-Systems alle 10 Sekunden schneller werden ...



Das Tutorial ist beendet. Das nächste ist Die Superklasse EduActor . Wenn du Feedback für uns hast, melde dich gerne.