diff --git a/GameProject/src/base/BreakoutGame.java b/GameProject/src/base/BreakoutGame.java
index d9cc8b5..34f90d3 100644
--- a/GameProject/src/base/BreakoutGame.java
+++ b/GameProject/src/base/BreakoutGame.java
@@ -19,7 +19,7 @@ public class BreakoutGame extends GameLoop {
@Override
public void defineLevels() {
this.resetLevels(); // removes Level1 added by superclass constructor
- this.addLevel(new BreakoutLevel1()); // FIXME add this as soon as your level exists
+ this.addLevel(new BreakoutLevel3()); // FIXME add this as soon as your level exists
}
/**
diff --git a/GameProject/src/controller/BreakoutController.java b/GameProject/src/controller/BreakoutController.java
new file mode 100644
index 0000000..87b5fa0
--- /dev/null
+++ b/GameProject/src/controller/BreakoutController.java
@@ -0,0 +1,28 @@
+package controller;
+
+import java.awt.event.KeyEvent;
+
+import gameobjects.GameObject;
+
+public class BreakoutController extends EgoController{
+
+ public BreakoutController(double width, double height) {
+ super(width, height);
+ }
+
+
+
+ @Override
+ public void onUp(KeyEvent kc, GameObject ego) {
+ }
+
+
+ @Override
+ public void onDown(KeyEvent kc, GameObject ego) {
+ }
+
+ @Override
+ public void onSpace(KeyEvent e, GameObject ego) {
+
+ }
+}
diff --git a/GameProject/src/controller/MineController.java b/GameProject/src/controller/MineController.java
index 5aa7e83..8558db4 100644
--- a/GameProject/src/controller/MineController.java
+++ b/GameProject/src/controller/MineController.java
@@ -4,7 +4,14 @@ import gameobjects.GameObject;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
-
+/**
+ * Stops GameObject movement at bottom of level and let it 'fly' in x-direction towards ego object.
+ * If the object flies outside of the level (by x-coordinate) it is removed.
+ *
+ * The behavior looks like a sinking sea mine, which stays at a certain depth and moves left/right to catch the player.
+ *
+ *
+ */
public class MineController extends ObjectController {
int rad = 3;
@@ -17,13 +24,19 @@ public class MineController extends ObjectController {
this.lineSpeed = lineSpeed;
}
+ /**
+ * Fetches ego object by name 'ego' from current level and determines it's x-position.
+ * The controlled GameObject will move towards this position (in x-direction only).
+ * y-direction speed is reduced to zero, if the objects reached lower bound of level (high y-values).
+ * Only deletes the object if it flies out of visible game area.
+ */
@Override
public void updateObject() {
if (gameObject.getY() >= this.getPlayground().getSizeY() - 10) {
this.gameObject.setVY(0);
if (xSpeed == 0.) {
- GameObject ego = getPlayground().getObject("ego");
+ GameObject ego = this.getPlayground().getObject("ego");
double egoXPos = ego.getX();
if (egoXPos > this.gameObject.getX()) {
xSpeed = 50;
@@ -38,9 +51,9 @@ public class MineController extends ObjectController {
}
if (this.gameObject.getX() < 0 || (this.gameObject.getX() > this.getPlayground().getSizeX())) {
logger.debug("deleting" + this.gameObject.getId());
- getPlayground().deleteObject(this.gameObject.getId());
+ this.getPlayground().deleteObject(this.gameObject.getId());
}
- applySpeedVector();
+ this.applySpeedVector();
}
}
diff --git a/GameProject/src/log4j2.xml b/GameProject/src/log4j2.xml
index e48b670..f21f70a 100644
--- a/GameProject/src/log4j2.xml
+++ b/GameProject/src/log4j2.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/GameProject/src/playground/BreakoutLevel0.java b/GameProject/src/playground/BreakoutLevel0.java
new file mode 100644
index 0000000..842c1a1
--- /dev/null
+++ b/GameProject/src/playground/BreakoutLevel0.java
@@ -0,0 +1,119 @@
+package playground;
+
+import java.awt.Color;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import collider.RectCollider;
+import controller.EgoController;
+import controller.ReboundController2;
+import gameobjects.FallingStar;
+import gameobjects.GameObject;
+import gameobjects.RectObject;
+
+/**
+ * simple solution example for Breakout game.
+ *
+ * not implemented: penalty if balls hits ground, no score for removed bricks, no bonus items, no
+ * lives.
+ *
+ *
+ */
+
+
+public class BreakoutLevel0 extends BreakoutLevelBase {
+
+ private static Logger logger = LogManager.getLogger(BreakoutLevelBase.class);
+
+
+ protected GameObject createEgoObject() {
+ RectObject ro = new RectObject("ego", this, 350, 550, 0, 0, 80, 10, Color.BLUE);
+ ro.generateColliders();
+ EgoController ec = new EgoController(80,10);
+ ro.addController(ec);
+ logger.info("ego created.");
+
+ return ro;
+ }
+
+
+ protected GameObject createBall() {
+ GameObject co = new FallingStar("ball1", this, 350, 350, 100, 100, Color.RED, 5);
+ co.addController(new ReboundController2());
+ logger.info("ball created.");
+ return co;
+ }
+
+
+ /**
+ * creates one brick. For
+ * collision {@link RectCollider} is used.
+ */
+ @Override
+ protected GameObject createBrick(int row, int column) {
+ double xSize = 60;
+ double ySize = 30;
+ double xStart = 40;
+ double yStart = 40;
+ double space = 5;
+ Color c = Color.BLUE;
+
+ RectObject ro = new RectObject("brick" + row + "/" + column, this, xStart + column * (xSize + space),
+ yStart + row * (ySize + space), 0, 0, xSize - 4, ySize - 4, c);
+ RectCollider rc = new RectCollider("egal", ro, xSize - 4, ySize - 4);
+ ro.addCollider(rc);
+
+ return ro;
+ }
+
+ /**
+ * lets ball bounce in Y direction, deletes brick.
+ */
+ @Override
+ protected void actionIfBallHitsBrick(GameObject ball, GameObject brick) {
+
+ ball.setVY(ball.getVY() * -1); // bounce effect for ball
+ this.deleteObject(brick.getId()); // remove brick from field
+ logger.debug("deleted brick " + brick.getId());
+
+ }
+
+
+ /**
+ * Let the ball bounce off in Y direction.
+ *
+ */
+ @Override
+ protected void actionIfBallHitsEgo(GameObject ball, GameObject ego) {
+ double ballY = ball.getY();
+ double egoY = ego.getY();
+ ball.setY(ballY < egoY ? ballY - 10 : ballY + 10); // radius 5 hard coded.
+ ball.setVY(ball.getVY() * -1);
+ logger.debug("ball bounces of ego object.");
+ }
+
+
+ /**
+ * Prepares a Breakout level with a 3 x 3 matrix of blocks on top. This method relies on the
+ * methods {@link #createEgo}, {@link #createBall} and {@link #createBrick}, among others.
+ *
+ * @param level String passes by the game engine (not used currently and can be ignored).
+ */
+ @Override
+ public void prepareLevel(String level) {
+ for (int y = 3; y < 6; y++) {
+ for (int x = 0; x < 3; x++) {
+ logger.trace("trying to create brick X, Y (" + x + "," + y + ")");
+ GameObject brick = this.createBrick(x, y);
+ this.addObject(brick);
+ }
+ }
+ this.ego = this.createEgoObject();
+ this.ball = this.createBall();
+ this.addObject(this.ego);
+ this.addObject(this.ball);
+ logger.info("level preperation succeeded.");
+
+ }
+
+
+}
diff --git a/GameProject/src/playground/BreakoutLevel2.java b/GameProject/src/playground/BreakoutLevel2.java
new file mode 100644
index 0000000..6e9ef2a
--- /dev/null
+++ b/GameProject/src/playground/BreakoutLevel2.java
@@ -0,0 +1,152 @@
+package playground;
+
+import java.awt.Color;
+import java.util.Random;
+
+import controller.BreakoutController;
+import controller.LimitedTimeController;
+import controller.ReboundController;
+import gameobjects.GameObject;
+import gameobjects.RectObject;
+
+public class BreakoutLevel2 extends BreakoutLevelBaseAdvanced {
+
+ @Override
+ protected int calcNrBricksX() {
+ return 6;
+ }
+
+ @Override
+ protected int calcNrBricksY() {
+ return 5;
+ }
+
+ @Override
+ protected double getBrickSizeX() {
+ return 60.0;
+ }
+
+ @Override
+ protected double getBrickSizeY() {
+ return 30.0;
+ }
+
+ @Override
+ protected double getBrickStartX() {
+ return 90.0;
+ }
+
+ @Override
+ protected double getBrickStartY() {
+ return 60.0;
+ }
+
+
+ /** Create Explosion effect with random Colors that lasts 2 Seconds.
+ *
+ * @param ball GameObject
+ * @param brick GameObject
+ */
+ @Override
+ protected void actionIfBallHitsBrick(GameObject ball, GameObject brick) {
+ //logger.info(brick.getId()+" is hitted and deleted!");
+ ball.setVY(ball.getVY() * -1.0);
+ int max = 240;
+ int min = -240;
+ Random rand = new Random();
+
+ for(int i = 0; i < 20; i++) {
+ Color randColor = new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat());
+ gameobjects.FallingStar explosion = new gameobjects.FallingStar("explosion"+gameTime+i, this, brick.getX(), brick.getY(), rand.nextInt(max - min + 1) + min, rand.nextInt(max - min + 1) + min, randColor, 2);
+ explosion.addController(new LimitedTimeController(gameTime, 2));
+ this.addObjectNow(explosion);
+
+ this.deleteObject(brick.getId());
+ }
+ }
+
+
+
+
+ /** Lets Ball bounce of from Ego.
+ * If the right or left end part is hitted, the ball bounces of in the end part direction doesn't matter from which site
+ *
+ * @param ball Gameobject
+ * @param ego GameObject
+ */
+ @Override
+ protected void actionIfBallHitsEgo(GameObject ball, GameObject ego) {
+ RectObject egoCopyCastedInRectObject = (RectObject) ego;
+ double egoMiddleX = ego.getX();
+ double ballX = ball.getX();
+ double egoWidth = egoCopyCastedInRectObject.getWidth();// Maybe an easier and cleaner way instead of casting an new
+ double egoHalfWidth = egoWidth / 2.0;
+
+ double egoEndPerc = 45.0;
+ double egoDistEndPartFromMiddle = (egoEndPerc * egoHalfWidth) / 100;
+ double egoEndPartStartLeft = egoMiddleX - egoDistEndPartFromMiddle;
+ double egoEndPartStartRight = egoMiddleX + egoDistEndPartFromMiddle;
+
+ if ((ballX < egoEndPartStartLeft && (ball.getVX() > 0.0)) || (ballX > egoEndPartStartRight && (ball.getVX() < 0.0))) {
+ ball.setVX(ball.getVX() * -1.0);
+ }
+
+ ball.setVY(ball.getVY() * -1.0);
+ }
+
+ /** Creates Ego object with an extra Controller for Breakout.
+ *
+ * @return ego
+ */
+ @Override
+ protected GameObject createEgoObject() {
+ RectObject ego = new RectObject("ego", this, 350, 550, 0, 0, 60, 10, Color.blue);
+ ego.addController(new BreakoutController(ego.getWidth(), ego.getHeight()));
+ ego.addCollider(new collider.RectCollider(ego.getId(), ego, ego.getWidth(), ego.getHeight()));
+ return ego;
+ }
+
+ /** Creates Ball.
+ *
+ * @return ball
+ */
+ @Override
+ protected GameObject createBall() {
+ gameobjects.FallingStar ball = new gameobjects.FallingStar("ball", this, 350, 350, 130, 130, Color.red, 5);
+ ball.addController(new ReboundController());
+ return ball;
+ }
+
+ /** Creates Brick with a random color.
+ *
+ * @param row int
+ * @param column int
+ *
+ * @return brick
+ */
+ @Override
+ protected GameObject createBrick(int row, int column) {
+
+ double rnd = Math.random();
+ Color clr;
+ if (rnd <= .25) {
+ clr = Color.red;
+ } else {
+ if (rnd <= .5) {
+ clr = Color.blue;
+ } else {
+ if (rnd <= .75) {
+ clr = Color.yellow;
+ } else {
+ clr = Color.green;
+ }
+ }
+ }
+
+ RectObject brick = new RectObject("brick" + row + column, this, getBrickStartX() + (row * (getBrickSizeX() * 2)), getBrickStartY() + (column * (getBrickSizeY() * 2)), 0, 0, getBrickSizeX(), getBrickSizeY(), clr);
+ brick.addCollider(new collider.RectCollider(brick.getId(), brick, brick.getWidth(), brick.getHeight()));
+
+ return brick;
+ }
+
+}
diff --git a/GameProject/src/playground/BreakoutLevel3.java b/GameProject/src/playground/BreakoutLevel3.java
new file mode 100644
index 0000000..4b91499
--- /dev/null
+++ b/GameProject/src/playground/BreakoutLevel3.java
@@ -0,0 +1,70 @@
+package playground;
+
+import java.awt.Color;
+
+import gameobjects.GameObject;
+
+public class BreakoutLevel3 extends BreakoutLevel2 {
+
+ gameobjects.TextObject textPoints, textLives;
+
+ /** Creates flags and TextObjects to display scores and Lives.
+ *
+ * @param level String
+ */
+ @Override
+ public void prepareLevel(String level) {
+ setGlobalFlag("points", 0);
+ getOrCreateGlobalFlag("lives", 3);
+ textPoints = new gameobjects.TextObject("textPoints", this, 50 , 10, 0, 0, "Score: 0", 10, Color.black);
+ textLives = new gameobjects.TextObject("textLives", this, 600 , 10, 0, 0, "Lives: "+(int)getOrCreateGlobalFlag("lives", 3), 10, Color.black);
+ this.addObject(textPoints);
+ this.addObject(textLives);
+
+ super.prepareLevel(level);
+ }
+
+ /** Sets the Score if a Brick is hitted.
+ *
+ * @param ball GameObject
+ * @param brick
+ */
+ @Override
+ protected void actionIfBallHitsBrick(GameObject ball, GameObject brick) {
+ super.actionIfBallHitsBrick(ball, brick);
+
+ setGlobalFlag("points", (int)(getGlobalFlag("points")) + 10);
+ textPoints.setText("Score: "+(int)getGlobalFlag("points"));
+
+ }
+
+ /** If the Ball goes under the Ego, Lives are decreased and Ball is set above Ego.
+ */
+ @Override
+ public void applyGameLogic() {
+ super.applyGameLogic();
+
+ if(ball.getY() > ego.getY()) {
+ setGlobalFlag("lives", (int)(getGlobalFlag("lives")) - 1);
+ textLives.setText("Lives: "+(int)getGlobalFlag("lives"));
+ if(ball.getVY() > 0) {
+ ball.setVY(ball.getVY() *- 1);
+ }
+ ball.setY(ego.getY()-20.0);
+ }
+ }
+
+ /** game ends if egoLives < 0 .
+ *
+ * @return gameOver boolean
+ */
+ @Override
+ public boolean gameOver() {
+ if((int)getGlobalFlag("lives") < 0) {
+ return true;
+ }
+ return false;
+ }
+}
+
+
diff --git a/GameProject/src/playground/BreakoutLevelBaseAdvanced.java b/GameProject/src/playground/BreakoutLevelBaseAdvanced.java
new file mode 100644
index 0000000..1022481
--- /dev/null
+++ b/GameProject/src/playground/BreakoutLevelBaseAdvanced.java
@@ -0,0 +1,98 @@
+package playground;
+
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+/**
+ * Advanced version of abstract {@link BreakoutLevelBase} providing a complete implementation of
+ * {@link #prepareLevel(String)}. Additionally abstract methods for number of bricks in X and Y
+ * direction are provided as well as abstract methods for brick sizes and start coordinates.
+ *
+ * @see #calcNrBricksX()
+ * @see #calcNrBricksY()
+ * @see #getBrickSizeX()
+ * @see #getBrickSizeY()
+ * @see #getBrickStartX()
+ * @see #getBrickStartY()
+ *
+ */
+public abstract class BreakoutLevelBaseAdvanced extends BreakoutLevelBase {
+
+ private static Logger logger = LogManager.getLogger(BreakoutLevelBaseAdvanced.class);
+
+
+ /**
+ * provides the number of bricks to be set in horizontal direction.
+ *
+ * @return positive value of how many bricks are to be next to each other in X direction
+ */
+ protected abstract int calcNrBricksX();
+
+ /**
+ * provides the number of bricks to be set in vertical direction.
+ *
+ * @return positive value of how many bricks are to be next to each other in Y direction
+ */
+ protected abstract int calcNrBricksY();
+
+ /**
+ * provides the length of one brick.
+ *
+ * @return positive value of how long a brick should be in X direction.
+ */
+ protected abstract double getBrickSizeX();
+
+ /**
+ * provides the height of one brick.
+ *
+ * @return positive value of how high a brick should be in Y direction.
+ */
+ protected abstract double getBrickSizeY();
+
+ /**
+ * provides the start coordinate of upper left corner (X value).
+ *
+ * @return positive value of the X coordinate to use as the starting point of the upper left
+ * corner of the brick set.
+ */
+ protected abstract double getBrickStartX();
+
+ /**
+ * provides the start coordinate of upper left corner (Y value).
+ *
+ * @return positive value of the Y coordinate to use as the starting point of the upper left
+ * corner of the brick set.
+ */
+ protected abstract double getBrickStartY();
+
+
+
+ /**
+ * Prepares a complete Breakout type level and uses the values provided by implementations of
+ * {@link #calcNrBricksX()} and {@link #calcNrBricksY()} to generate the stone matrix.
+ * Furthermore, it relies on the methods {@link #createEgoObject()}, {@link #createBall} and {@link #createBrick},
+ * which are meant to be overwritten in subclasses.
+ * Attention: For collision detection bricks created by {@link #createBrick(int, int)} need to have the String 'brick' in ID.
+ *
+ * @see LevelBreakoutBase#prepareLevel(String) for further information.
+ *
+ * @param level String passes by the game engine (not used currently and can be ignored).
+ *
+ */
+ @Override
+ public void prepareLevel(String level) {
+
+ for (int y = 0; y < this.calcNrBricksY(); y++) {
+ for (int x = 0; x < this.calcNrBricksX(); x++) {
+ logger.trace("trying to create brick X, Y (" + x + "," + y + ")");
+ this.addObject(this.createBrick(x, y));
+ }
+ }
+ this.ego = this.createEgoObject();
+ this.ball = this.createBall();
+ this.addObject(this.ego);
+ this.addObject(this.ball);
+ logger.info("level preperation succeeded.");
+ }
+
+}