Version vom 29. Dezember 2020, 13:46 Uhr von Mike (Diskussion | Beiträge) (Jump'n'Run-Physik)


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 gemeinsame Fähigkeiten aller grafisch darstellbaren Objekte kennen
  • Gewinnst du einen Überblick über die Möglichkeiten der eingebauten Physik

Super-Klasse EduActor

EA Demo

Die Super-Klasse EduActor ist im wahrsten Sinne die Mutter aller grafisch darstellbaren Klassen der Edu-Variante der Engine Alpha. Es handelt sich um eine abstrakte Klasse von der man selbst keine Objekte erzeugen kann. Aber in dieser abstrakten Klasse werden sehr viele Methoden und Verhaltensweisen aller grafisch darstellbaren Objekte definiert. Jede Klasse, deren Objekte auf der Bühne sichtbar werden, hat von dieser Klasse geerbt. Das bringt folgende Vorteile:

  • Alle Klassen (KREIS, RECHTECK, DREIECK, FIGUR, TEXT) verfügen über eine Menge an gemeinsamen Methoden.
  • Der Klassen-Bezeichner EduActor kann als Platzhalter für jede der oben genannten Klassen verwendet werden. Wann immer du auf diesen Datentyp z.B. beim Parameter von schneidet(EduActor ea) oder schneidet(Eduactor ea) stößt, kannst du beliebige Objekte der oben genannten Klassen einsetzen.


grundlegende Methoden

  • verschieben(double deltaX, double deltaY)
    
    (Maßeinheit ist "Bildschirm-Meter")
  • drehen(double grad)
    
    (in Winkelgrad)
  • setzeDrehwinkel(double grad)
    
    (Maßeinheit ist Winkelgrad)
  • nenneDrehwinkel() : double
    
    (Maßeinheit ist Winkelgrad)
  • setzeMittelpunkt(double x, double y)
    
    (Maßeinheit ist "Bildschirm-Meter". Ursprung in der Mitte der Bühne. Achsen wie in Mathe.)
  • setzeSichtbar(boolean sichtbar)
    
    (sichtbar=true, unsichtbar=false)
  • nenneSichtbar() : boolean
    
    (sichtbar = true, unsichtbar=false)
  • beinhaltetPunkt(double x, double y): boolean
    
    (Maßeinheit ist "Bildschirm-Meter". JA=true, NEIN=false)
  • schneidet(EduActor ea)
    
    (Es kann jedes grafisch darstellbare Objekt übergeben werden.)
  • setzeTransparenz(double wert
    
    (0 = ohne Transparenz, 1 = völlige Transparenz, also unsichtbar)
  • nenneTransparenz() : double
    
    (0 = ohne Transparenz, 1 = völlige Transparenz, also unsichtbar)
  • animiereTransparenz(double sekunden, double transparenzNachher)
    
    (Vom jetzigen Transparenz-Wert wird in der angegebenen Zeit zum neuen Transparenz-Wert "übergeblendet")

Anordnung und Ebenen

Normalerweise werden Objekte, die zuerst angelegt werden weiter hinten gezeichnet als später angelegte Objekte. Das heißt, dass später gezeichnete Objekte früher gezeichnete Objekte überdecken. Man kann aber auch gezielt Ebenen verwenden, um selbst zu definieren, welches Objekt von welchem anderen Objekt verdeckt wird, bzw. das andere Objekt überdeckt. Diese kann auch zur Laufzeit des Programms verändert werden und so z.B. Objekte von vorne nach hinten oder umgekehrt versetzt werden.

Ball fällt scheinbar in Eimer

Hierzu gibt es die folgenden beiden Methoden:

  • setzeEbenenposition(int positiion)
    
    (0 ist ganz hinten, größere Werte liegen weiter vorne.)
  • nenneEbenenposition() : int
    
    (Objekte mit höherem Wert liegen weiter vorne.)

Hier der nötige Quellcode:

public class Test
extends SPIEL
{
    private FIGUR eimer_unten;
    private FIGUR eimer_oben;
    private KREIS ball;
    
    public Test()
    {
        this.eimer_oben = new FIGUR( "standard" , "Eimer_rot_oben.png" , 1, 1 );
        this.eimer_oben.setzeMittelpunkt( 0 , -8+2.6 );
        this.eimer_oben.setzeEbene( 0 ); // hinten
        
        this.eimer_unten = new FIGUR( "standard" , "Eimer_rot_unten.png" , 1 , 1 );
        this.eimer_unten.setzeMittelpunkt( 0 , -8 );
        this.eimer_unten.setzeEbene( 2 ); // vorne
        
        this.ball = new KREIS( 1 );
        this.ball.setzeMittelpunkt( 0 , 3 );
        this.ball.setzeFarbe( "gelb" );
        this.ball.setzeEbene( 1 ); // zwischen "hinten" und "vorne"
    }
    
    @Override
    public void tasteReagieren( int code )
    {
        this.ball.macheAktiv(); // fallen lassen
    }
}

Hier die Bild-Dateien zum Download: Eimer rot oben.png Eimer rot unten.png

Jump'n'Run-Physik

Die Jump'n'Run-Physik ist auf die einfachen Bedürfnisse von Jump'n'Run-Spielen ausgelegt und kennt drei verschiedene Zustände eines EduActor:

  • neutral : Zeigt keinerlei Wechselwirkung mit anderen EduActor-Objekten, reagiert aber auf Methode schneidet(...).
  • dynamisch : Unterliegt der Schwerkraft und wird von statischen EduActor-Objekten aufgehalten oder kann auf ihnen stehen und von ihnen abspringen.
  • statisch : Stellt für dynamische EduActor-Objekte ein Hindernis bzw. einen Boden dar, kann dynamische EduActor-Objekte verdrängen, verschieben oder mitnehmen.

Frisch erzeugte EduActor-Objekte befinden sich immer im Zustand neutral.

Hierzu werden die folgenden Methoden zur Verfügung gestellt:

  • macheDynamisch()
    Hiermit wird ein EduActor-Objekt dynmaisch gemacht. Es unterliegt nun auch der Schwerkraft und kann keine statischen EduActor-Objekte mehr durchdringen.
  • macheStatisch()
    Hiermit wird ein EduActor-Objekt statisch gemacht. Es hält nun alle dynamischen EduActor-Objekte auf bzw. nimmt sie mit.
  • macheNeutral()
    Hiermit wird ein EduActor-Objekt neutral gemacht. Es nimmt nun nicht mehr an der Jump'n'Run-Physik Teil.
  • steht()
    Überprüft, ob ein dynamisches EduActor-Objekt auf irgendeinem statischen EduActor-Objekt steht.
  • stehtAuf(EduActor ea)
    Überprüft, ob ein dynamisches EduActor-Objekt auf einenm bestimmten statischen EduActor-Objekt steht.
  • springe(double stärke)
    Ein dynamisches EduActor-Objekt, das gerade auf irgendeinem statischen EduActor-Objekt steht, kann von diesem abspringen. Also übergebener Wert ist 5 ein guter Startwert.
  • setzeRotationBlockiert(boolean blockiert)
    Standardmäßig drehen sich EduActor-Objekte nicht während der Teilnahme an der Physik. Hiermit können z.B dynamische EduActor-Objekte, wenn sie auf dem Rand eines statischen EduActor-Objekts stehen, überkippen. Sie können nun auch "umgehauen" werden.
Jump'n'Run Physik Demo

Demo-Code "Jump'n'Run"

public class JumpRun 
extends SPIEL
{
    private FIGUR spieler , boden_1 , boden_2 ;
    
    public JumpRun()
    {
        for ( int i=0 ; i<20 ; i++ )
        {
            FIGUR boden = new FIGUR( "Wiese.png" );
            boden.setzeMittelpunkt( -20+i*2.1 , -9 );
            boden.macheStatisch();
        }
        
        boden_1 = new FIGUR( "Wiese2.png" );
        boden_1.setzeMittelpunkt( 0.5 , -4 ) ;
        boden_1.macheStatisch();
        
        boden_2 = new FIGUR( "Wiese2.png" );
        boden_2.setzeMittelpunkt( 6.5 , 1 ) ;
        boden_2.macheStatisch();
        
        spieler = new FIGUR( "traveler_idle.gif" ) ;
        spieler.setzeMittelpunkt( -5 , -5 );
        spieler.macheDynamisch();
    }
    
    @Override
    public void tasteReagieren( int code )
    {
        switch( code )
        {
            case TASTE.RAUF :   spieler.springe( 10 ); 
                                break;
            case TASTE.LINKS:   spieler.setzeGeschwindigkeit( -2 , 0 ); 
                                spieler.spiegelnHorizontal( true ) ;
                                break;
            case TASTE.RECHTS:  spieler.setzeGeschwindigkeit( 2 , 0 );  
                                spieler.spiegelnHorizontal( false ) ;
                                break;
            case TASTE.RUNTER:  spieler.setzeGeschwindigkeit( 0 , 0 );
                                break;
        }
    }
}
Ball springt in Eimer

Demo-Code "Simulation"

public class Eimer 
{
    private FIGUR unten;
    private FIGUR oben;
    private TEXT beschriftung;
    private int zaehler;
    // unsichtbare "Ränder" des Eimers zum abprallen
    private RECHTECK links;
    private RECHTECK rechts;
    // unsichtbare "Lichtschranke" zum zählern der Bälle
    private KREIS detektor;
    

    public Eimer( int x , int y , String farbe )
    {
        
        if ( farbe.equals("rot") )
        {
            this.oben = new FIGUR( "standard" , "Eimer_rot_oben.png" , 1, 1 );
            this.oben.setzeMittelpunkt( x , y+2.6 );
            this.oben.setzeEbene( 0 );
            this.unten = new FIGUR( "standard" , "Eimer_rot_unten.png" , 1 , 1 );
            this.unten.setzeMittelpunkt( x , y );
            this.unten.setzeEbene( 2 );
            this.beschriftung = new TEXT( x , y , 1.5 , 0 );
            this.beschriftung.setzeSchriftHoehe( 1.5 );
            this.beschriftung.setzeFarbe( "blau" );
            this.beschriftung.setzeEbenenposition( 3 );
        }
        else 
        {
            this.oben = new FIGUR( "standard" , "Eimer_blau_oben.png" , 1, 1 );
            this.oben.setzeMittelpunkt( x , y+2.6 );
            this.oben.setzeEbene( 0 );
            this.unten = new FIGUR( "standard" , "Eimer_blau_unten.png" , 1 , 1 );
            this.unten.setzeMittelpunkt( x , y );
            this.unten.setzeEbene( 2 );
            this.beschriftung = new TEXT( x , y , 1.5 , 0 );
            this.beschriftung.setzeSchriftHoehe( 1.5 );
            this.beschriftung.setzeFarbe( "gelb" );
            this.beschriftung.setzeEbenenposition( 3 );
            
        }
        
        // linke Eimer-Kante zum abprallen
        this.links = new RECHTECK( 0.1 , 4 );
        this.links.setzeMittelpunkt( x-3 , y+0.9 );
        this.links.setzeSichtbar( false );
        this.links.setzeDrehwinkel( 11.5 );
        this.links.setzeEbenenposition( 0 );
        this.links.macheStatisch();
        this.links.setzeElastizitaet( 0.5 );
        // rechte Eimer-Kante zum abprallen
        this.rechts = new RECHTECK( 0.1 , 4 );
        this.rechts.setzeMittelpunkt( x+3 , y+0.9 );
        this.rechts.setzeSichtbar( false );
        this.rechts.setzeDrehwinkel( -11.5 );
        this.rechts.setzeEbenenposition( 0 );
        this.rechts.macheStatisch();
        this.rechts.setzeElastizitaet( 0.5 );
        // Kugel-Zähler
        this.detektor = new KREIS( 1 );
        this.detektor.setzeSichtbar( false );
        this.detektor.setzeMittelpunkt( x , y-3.5 );
        
        this.zaehler = 0;
    }
    
    public Eimer()
    {
        this(0,0,"blau");
    }

    
    public void erhoeheZaehler()
    {
        this.zaehler += 1;
        this.beschriftung.setzeInhalt( ""+(int)this.zaehler );
    }
    
    
    public void setzeZaelher( int wert )
    {
        this.zaehler = wert;
        this.beschriftung.setzeInhalt( wert );
    }
    
    
    public int nenneZaehler()
    {
        return this.zaehler;
    }
    
    
    public void erkenneObReingefallen( Kugel k )
    {
        if ( k.schneidet( this.detektor ) )
        {
            k.setzeMittelpunkt( 0 , -40 );
            this.erhoeheZaehler();
        }
    }
}

Animationen

... bald ... Animationen längs Geraden oder Kreisen ...


Kinematische Physik

... bald ... Methode macheKinematisch()


individuelle Kollisions-Formen

Der Kollisions-Bereich eines EduActor ist stantdardmäßig ein umhüllendes Rechteck. Das führt nicht immer zu den gewünschten Interaktionen mit anderen Objekten. Deshalb kann man jedem EduActor auch eine individuelle Kollisions-Form - bestehend aus Rechtecken, Kreisen und Polygonen - erstellen. ... bald ... Methode setzeKollisionsformen(...) ...


Verbindungen zwischen Objekten

Es ist auch möglich, mehrere EduActor-Objekte miteinander auf verschiedene Arten zu verbinden. ... bald ...


Methoden zeitverzögert ausführen

Es ist auch möglich, jede beliebige Methode eines EduActor-Objekts zeitverzögert und damit nebenläufig zum restlichen Code anzusetzen. ... bald ...



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