Beispiel Raindops OOP
Raindrops OOP ist die objektorientierte Umsetzung eines kleines Spiels, bei dem Regentropfen mit einem Eimer gefangen werden müssen. Das Beispiel zeigt die Umsetzung eines etwas komplexeren Spiels mittels des ShapesLayer. Eine nicht-objektorientierte Variante, die den DrawingLayer nutzt, wird im Beispiel zm_raindrops zu finden sein.
This commit is contained in:
parent
ac56393998
commit
9d78686470
|
@ -0,0 +1,13 @@
|
|||
import schule.ngb.zm.shapes.Picture;
|
||||
|
||||
public class Bucket extends Picture {
|
||||
|
||||
public Bucket( int x, int y ) {
|
||||
super(x, y, "bucket.png");
|
||||
}
|
||||
|
||||
public boolean contains( Drop pDrop ) {
|
||||
return getBounds().contains(pDrop.getX(), pDrop.getY());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import schule.ngb.zm.Updatable;
|
||||
import schule.ngb.zm.shapes.Picture;
|
||||
|
||||
public class Drop extends Picture implements Updatable {
|
||||
|
||||
public static final double SPEED_PIXELPERSECOND = 100.0;
|
||||
|
||||
public static final double SPEED_INCREASE = 1.2;
|
||||
|
||||
public static final int START_Y = 40;
|
||||
|
||||
|
||||
private double speed = SPEED_PIXELPERSECOND;
|
||||
|
||||
private boolean active = false;
|
||||
|
||||
public Drop() {
|
||||
super(0, 0, "raindrop.png");
|
||||
hide();
|
||||
}
|
||||
|
||||
public void increaseSpeed() {
|
||||
this.speed *= SPEED_INCREASE;
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
moveTo(random(Raindrops.GAME_BORDER, Raindrops.GAME_WIDTH - Raindrops.GAME_BORDER), START_Y);
|
||||
show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( double delta ) {
|
||||
y += speed * delta;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
# Zeichenmaschine: Raindrops
|
||||
|
||||
Raindrops ist ein einfaches Spiel, bei dem Regentropfen vom Himmel fallen,
|
||||
die von der Spieler:in mit einem Eimer aufgefangen werden müssen.
|
||||
|
||||
Das Spiel wird nach und nach schwerer (mehr Tropfen, höheres Tempo), bis die
|
||||
Spieler:in zu viele Tropfen fallen gelassen hat.
|
||||
|
||||
Diese Variante des Spiels ist Objektorientiert mit dem ShapesLayer implementiert.
|
||||
Eine nicht OOP Version ist im Beispielprojekt zm_raindrops zu finden.
|
||||
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
import schule.ngb.zm.Zeichenmaschine;
|
||||
import schule.ngb.zm.shapes.Text;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
public class Raindrops extends Zeichenmaschine {
|
||||
|
||||
//@formatter:off
|
||||
// Einstellungen für das Spiel
|
||||
|
||||
// Breite / Höhe des Spielfensters.
|
||||
public static final int GAME_WIDTH = 400;
|
||||
public static final int GAME_HEIGHT = 600;
|
||||
// Breite des Randes (dort werden keine Tropfen erstellt).
|
||||
public static final int GAME_BORDER = 10;
|
||||
|
||||
// Anzahl Tropfen zu Beginn des Spiels.
|
||||
public static final int GAME_START_DROPS = 5;
|
||||
// Maximale Anzahl Tropfen im Spiel.
|
||||
public static final int GAME_MAX_DROPS = 12;
|
||||
// Anzahl gefangenere Tropfen, ab der ein neuer Level anfängt.
|
||||
public static final int GAME_NEXT_LEVEL_AT = 10;
|
||||
// Anzahl Tropfen, die fallen gelassen werden dürfen,
|
||||
// bevor das Spiel vorbei ist.
|
||||
public static final int GAME_MAX_DROPPED = 13;
|
||||
//@formatter:on
|
||||
|
||||
public static void main( String[] args ) {
|
||||
new Raindrops();
|
||||
}
|
||||
|
||||
/**
|
||||
* Array der Tropfen-Objekte.
|
||||
*/
|
||||
private Drop[] drops;
|
||||
|
||||
/**
|
||||
* Das Eimer-Objekt.
|
||||
*/
|
||||
private Bucket bucket;
|
||||
|
||||
/**
|
||||
* Anzahl Tropfen, die aktuell im Spiel sind.
|
||||
*/
|
||||
private int noOfDrops = GAME_START_DROPS;
|
||||
|
||||
/**
|
||||
* Anzahl gefangener / fallen gelassener Tropfen.
|
||||
*/
|
||||
private int dropped = 0, catched = 0;
|
||||
|
||||
/**
|
||||
* Text-Objekte für die Anzeige der gefangenen / fallen gelassenen Tropfen.
|
||||
*/
|
||||
private Text textDropped, textCatched;
|
||||
|
||||
/**
|
||||
* Initialisierung des Spiels und der benötigten Objekte.
|
||||
*/
|
||||
public void setup() {
|
||||
setSize(GAME_WIDTH, GAME_HEIGHT);
|
||||
setTitle("ZM: Raindrops");
|
||||
|
||||
// Hintergrund blaugrau
|
||||
background.setColor(129, 174, 206);
|
||||
|
||||
// Hintergrundbild zeichnen (DrawingLayer)
|
||||
drawing.setFillColor(0, 144, 81);
|
||||
drawing.noStroke();
|
||||
drawing.rect(0, height - 40, width, 40, NORTHWEST);
|
||||
|
||||
// Eimer-Objekt erstellen
|
||||
bucket = new Bucket(width / 2, height - 60);
|
||||
bucket.scale(.25);
|
||||
shapes.add(bucket);
|
||||
|
||||
// Tropfen-Objekte erstellen
|
||||
// Die maximale Anzahl Tropfen kann durch GAME_MAX_DROPS eingestellt werden
|
||||
// Es werden alle Tropfen erstellt, anber nur die ersten noOfDrops
|
||||
// Objekt im Spiel angezeigt.
|
||||
drops = new Drop[GAME_MAX_DROPS];
|
||||
for( int i = 0; i < drops.length; i++ ) {
|
||||
drops[i] = new Drop();
|
||||
drops[i].scale(.1);
|
||||
shapes.add(drops[i]);
|
||||
}
|
||||
|
||||
// Die ersten noOfDrops Tropfen zu Beginn anzeigen.
|
||||
// Die Tropfen werden mit zufälliger x-Koordinate etwas versetzt
|
||||
// übereinander positioniert, damit sie nicht alle gleichzeitig fallen.
|
||||
for( int i = 0; i < noOfDrops; i++ ) {
|
||||
drops[i].moveTo(
|
||||
random(GAME_BORDER, GAME_WIDTH - GAME_BORDER),
|
||||
Drop.START_Y - i * (2 * Drop.START_Y) - random(-10, 10)
|
||||
);
|
||||
drops[i].activate();
|
||||
drops[i].show();
|
||||
}
|
||||
|
||||
// Erstellen der Text-Objekte für dei Zähler.
|
||||
textCatched = new Text(10, 60, "0");
|
||||
textCatched.setFontsize(64);
|
||||
textCatched.setAnchor(NORTHWEST); //linksbündig
|
||||
shapes.add(textCatched);
|
||||
textDropped = new Text(width - 10, 60, "0");
|
||||
textDropped.setFontsize(64);
|
||||
textDropped.setAnchor(NORTHEAST); // rechtsbündig
|
||||
shapes.add(textDropped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hier passiert die Spiel-Logik. Die Position des Eimers und der Tropfen
|
||||
* wird aktualisiert. Es wird geprüft, ob ein Tropfen mit dem Eimer
|
||||
* kollidiert oder den Boden erreicht hat.
|
||||
*
|
||||
* @param delta
|
||||
*/
|
||||
public void update( double delta ) {
|
||||
// Position des Eimers auf Mausposition setzen.
|
||||
if( mouseX < 0 ) {
|
||||
// Stopp am linken Rand
|
||||
bucket.setX(0);
|
||||
} else if( mouseX > width ) {
|
||||
// Stopp am rechten Rand
|
||||
bucket.setX(width);
|
||||
} else {
|
||||
bucket.setX(mouseX);
|
||||
}
|
||||
|
||||
// Die Position der Tropfen aktualisieren und Kollisionen prüfen.
|
||||
for( int i = 0; i < noOfDrops; i++ ) {
|
||||
drops[i].update(delta);
|
||||
|
||||
if( drops[i].getY() >= height - 40 ) {
|
||||
// Tropfen hat Boden erreicht!
|
||||
dropped += 1;
|
||||
textDropped.setText("" + dropped);
|
||||
drops[i].reset();
|
||||
} else if( bucket.contains(drops[i]) ) {
|
||||
// Tropfen wurde gefangen!
|
||||
catched += 1;
|
||||
textCatched.setText("" + catched);
|
||||
drops[i].reset();
|
||||
|
||||
// Wurde ein Tropfen gefangen (und nur dann) wird geprüft, ob
|
||||
// das nächste Level erreicht wurde.
|
||||
if( catched > 0 && (catched % GAME_NEXT_LEVEL_AT) == 0 ) {
|
||||
// Falls noch nicht alle Tropfen im Spiel, aktiviere einen
|
||||
// weiteren.
|
||||
if( noOfDrops < drops.length ) {
|
||||
noOfDrops += 1;
|
||||
drops[noOfDrops - 1].activate();
|
||||
drops[noOfDrops - 1].reset();
|
||||
}
|
||||
|
||||
// Geschwindigkeit aller Tropfen erhöhen.
|
||||
for( int j = 0; j < drops.length; j++ ) {
|
||||
drops[j].increaseSpeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prüfen, ob das Spiel verloren wurde.
|
||||
if( dropped >= GAME_MAX_DROPPED ) {
|
||||
stop(); // Stoppt den Game-Loop und ruft dann teardown() auf.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wird aufgerufen, nachdem das Spiel gestoppt wurde und zeigt den Game Over
|
||||
* Bildschirm an.
|
||||
*/
|
||||
public void teardown() {
|
||||
// Alle Formen (Eimer, Tropfen, Texte) entfernen.
|
||||
shapes.removeAll();
|
||||
|
||||
// "Game Over" Text
|
||||
Text gameOver = new Text(width / 2, 300, "Game Over");
|
||||
gameOver.setFontsize(64);
|
||||
shapes.add(gameOver);
|
||||
|
||||
// Ergebnis anzeigen (Anzahl gefangener Tropfen, Spielzeit in Sekunden).
|
||||
Font f = new Font(Font.SANS_SERIF, Font.PLAIN, 32);
|
||||
shapes.add(new Text(width / 2, 360, "Catched: " + catched, f));
|
||||
shapes.add(new Text(width / 2, 360 + f.getSize(), "Time: " + (runtime / 1000.0), f));
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
|
@ -0,0 +1,58 @@
|
|||
#BlueJ package file
|
||||
dependency1.from=TIXY
|
||||
dependency1.to=MyTIXY
|
||||
dependency1.type=UsesDependency
|
||||
dependency2.from=TIXY
|
||||
dependency2.to=Dot
|
||||
dependency2.type=UsesDependency
|
||||
dependency3.from=MyTIXY
|
||||
dependency3.to=Dot
|
||||
dependency3.type=UsesDependency
|
||||
dependency4.from=Dot
|
||||
dependency4.to=TIXY
|
||||
dependency4.type=UsesDependency
|
||||
editor.fx.0.height=728
|
||||
editor.fx.0.width=1037
|
||||
editor.fx.0.x=95
|
||||
editor.fx.0.y=53
|
||||
objectbench.height=94
|
||||
objectbench.width=776
|
||||
package.divider.horizontal=0.6
|
||||
package.divider.vertical=0.8305369127516778
|
||||
package.editor.height=488
|
||||
package.editor.width=661
|
||||
package.editor.x=374
|
||||
package.editor.y=158
|
||||
package.frame.height=660
|
||||
package.frame.width=800
|
||||
package.numDependencies=4
|
||||
package.numTargets=3
|
||||
package.showExtends=true
|
||||
package.showUses=true
|
||||
project.charset=UTF-8
|
||||
readme.height=60
|
||||
readme.name=@README
|
||||
readme.width=48
|
||||
readme.x=10
|
||||
readme.y=10
|
||||
target1.height=70
|
||||
target1.name=TIXY
|
||||
target1.showInterface=false
|
||||
target1.type=ClassTarget
|
||||
target1.width=120
|
||||
target1.x=120
|
||||
target1.y=60
|
||||
target2.height=70
|
||||
target2.name=MyTIXY
|
||||
target2.showInterface=false
|
||||
target2.type=ClassTarget
|
||||
target2.width=120
|
||||
target2.x=200
|
||||
target2.y=210
|
||||
target3.height=70
|
||||
target3.name=Dot
|
||||
target3.showInterface=false
|
||||
target3.type=ClassTarget
|
||||
target3.width=120
|
||||
target3.x=420
|
||||
target3.y=140
|
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
Loading…
Reference in New Issue