Das Spiel wird mit einem Mausklick auf den Schläger oder auf einen Levelbutton gestartet. Die Steuerung erfolgt mit Links- bzw. Rechtsbewegung der Maus. Mit den Levelbuttons kann vor dem Spielbeginn oder während des Spiels die Geschwindigkeit geändert werden (Level 3 ist am schnellsten). Die Anzahl der erreichten Punkte wird in der Titelleiste angezeigt, die Zeit rechts unten. Nach dem "Game over" kann das Spiel mit einem Mausklick erneut gestartet werden. |
Programmcode für lokale Bearbeitung downloaden: BreakoutGame.zip
Der Klassendesign besteht aus fünf Klassen: Applikationsklasse BreakoutGame.java, Breaker.java, BreakerBar.java, Brick.java und LevelButton.java. Das Layout, Maus- und Spielablaufsteuerung sind in der Applikationsklasse implementiert. In der Klasse Breaker wird geregelt, wie der Ball an den Wänden reflektiert werden soll. Die Klasse LevelButton enthält die Geschwindigkeites-Regelung.
Programmcode
// BreakoutGame.java import ch.aplu.jgamegrid.*; import java.awt.*; public class BreakoutGame extends GameGrid implements GGMouseListener, GGActorCollisionListener { private int points; private static final int TIMELIMIT = 120; //in seconds private static final int STARTSPEED = 35; private long startTime; private BreakerBar bar; private Breaker breaker; private boolean gameOver, startingStage; private static final Location startLocation = new Location(400, 463); public BreakoutGame() { super(800, 550, 1, false); getBg().setBgColor(Color.black); bar = new BreakerBar(); bar.setCollisionRectangle(new Point(0, 0), 60, 15); breaker = new Breaker(this); breaker.setCollisionCircle(new Point(0, 0), 10); addActor(breaker, startLocation); breaker.addCollisionActor(bar); breaker.addActorCollisionListener(this); reset(); setSimulationPeriod(STARTSPEED); for (int i = 1; i <= 3; i++) { LevelButton lvlBtn = new LevelButton(i); addActor(lvlBtn, new Location(i * 110 - 50, nbVertCells - 25)); if (i == 1) //start with level 1 lvlBtn.show(1); } addActor(bar, new Location(nbHorzCells / 2, nbVertCells - 70)); addMouseListener(this, GGMouse.move | GGMouse.lClick); getBg().setPaintColor(Color.red); show(); doRun(); } public void act() { if (!(startingStage || gameOver)) { getBg().clear(); long timeLeft = (TIMELIMIT * 1000 + startTime - System.currentTimeMillis()) / 1000; if (timeLeft > 0) getBg().drawText(timeLeft + " seconds left", new Point(600, 540)); else gameOver(); } } public void reset() { setTitle("Breaker-Game, start by clicking. Break as many bricks as possible in " + TIMELIMIT + " seconds"); breaker.setActEnabled(false); getBg().clear(); points = 0; startTime = 0; gameOver = false; startingStage = true; removeActors(Brick.class); breaker.setLocation(startLocation); bar.setLocation(new Location(nbHorzCells / 2, nbVertCells - 70)); breaker.setDirection((Math.random() * 120 - 60) + 270); //upwards, but random for (int j = 0; j < 10; j++) { for (int i = 0; i < 13; i++) { if (Math.random() < 0.85) { //erstelle nur 85 % der Steine Brick brick = new Brick(j / 3); brick.setCollisionRectangle(new Point(0, 0), 50, 20); breaker.addCollisionActor(brick); addActor(brick, new Location(i * 51 + 90, 21 * j + 60)); } } } } public boolean mouseEvent(GGMouse mouse) { switch (mouse.getEvent()) { case GGMouse.lClick: if (gameOver) { reset(); } else if (startTime == 0) { //start game startTime = System.currentTimeMillis(); breaker.setActEnabled(true); startingStage = false; } break; case GGMouse.move: bar.setX(mouse.getX()); if (startingStage) breaker.setX(mouse.getX()); break; } return true; } public int collide(Actor actor1, Actor actor2) { double dir = actor1.getDirection(); //how did they hit each other? double hitDirection = actor2.getLocation().getDirectionTo(actor1.getLocation()); System.out.println("Collision! " + actor1 + " vs " + actor2 + " hitDir: " + hitDirection); System.out.println("direction before: " + actor1.getDirection()); if (actor2.getClass().equals(Brick.class)) { //hit brick actor1.setDirection(reflectPhysicallyCorrect(actor1.getLocation(), actor2.getLocation(), dir)); points += 10; if (getActors(Brick.class).size() == 0) gameOver(); else setTitle("Breaker-Game Points: " + points); removeActor(actor2); System.out.println("direction after: " + actor1.getDirection()); return 0; //be immediately ready for next collision } else { //hit pad if (actor1.getY() <= actor2.getY()) // breaker has to be higher than bar actor1.setDirection(reflectWithHitZones(actor1.getLocation(), actor2.getLocation())); return 10; //don't hit for another 10 cycles } } private double reflectWithHitZones(Location loc1, Location loc2) { int distance = loc1.x - loc2.x; int dir = (int)(distance * 2.5); System.out.println(distance + " -> winkel: " + dir); return dir - 90; //TODO: what if exactly 90° } private double reflectPhysicallyCorrect(Location loc1, Location loc2, double dir) { int xMovement = loc2.x - loc1.x; int yMovement = loc2.y - loc1.y; if (Math.abs(xMovement) <= 25) //von oben und unten dir = 360 - dir; else if (Math.abs(yMovement) <= 10) //von links und rechts dir = 180 - dir; else System.out.println("omg, none of the cases!"); return dir; } public void gameOver() { gameOver = true; breaker.setActEnabled(false); long elapsedTime = (System.currentTimeMillis() - startTime) / 1000; setTitle("Game Over! " + points + " points " + " in " + elapsedTime + " seconds. Reset by clicking."); } public static void main(String[] args) { new BreakoutGame(); } } // -------class Breaker ------------- class Breaker extends Actor { private double speed; private BreakoutGame gg; public Breaker(BreakoutGame gg) { super("sprites/breaker.png"); this.gg = gg; } public void act() { double dir = getDirection(); if (getY() > this.gameGrid.nbVertCells - 60) { //breaker has dropped gg.gameOver(); } //collision with wall: if (getX() < 10) { dir = 180 - dir; } if (getX() > 790) { dir = 180 - dir; } if (getY() < 10) { dir = 360 - dir; } setDirection(dir); move(); } } // -------class Breakerbar -------------- class BreakerBar extends Actor { public BreakerBar() { super("sprites/bar2.png"); } } // ---------class Brick -------------------- class Brick extends Actor { public Brick(int sprite) { super("sprites/brickS.png", 4); show(sprite); } } // ---------class LevelButton ---------------- class LevelButton extends Actor implements GGMouseTouchListener { private int level; public LevelButton(int level) { super("sprites/Level" + level + ".png", 2); this.level = level; setMouseTouchImage(); this.addMouseTouchListener(this, GGMouse.lClick); } public void mouseTouched(Actor actor1, GGMouse arg1, Point arg2) { for (Actor act : gameGrid.getActors(LevelButton.class)) //set all buttons to gray act.show(0); this.show(1); switch (level) //change speed { case 1: gameGrid.setSimulationPeriod(35); break; case 2: gameGrid.setSimulationPeriod(25); break; case 3: gameGrid.setSimulationPeriod(15); break; } } } |