/**
* @author Matthias Utrata, 3AI
* SEW-Projekt: Breakout
*/
/**
* Benötigte Imports
*/
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
* Breakout-Klasse
*/
public class Breakout extends Application {
public static void main(String[] args) {
launch(args);
}
/**
* Variablen zur Bestimmung der Größe, des Spielfeldes
*/
private static final int width = 700;
private static final int height = 900;
/**
* boolean, der beurteilt, ob das Spiel gestartet wurde.
*/
private boolean gameStarted;
/**
* Variablen, die den Durchmesser des Balls, die Breite und Höhe des Schlägers, sowie der Ziele angeben.
*/
private final int durch = 10;
private final int paddleW = 50;
private final int paddleH = 10;
private final int brickH = 15;
private final int brickW = 80;
/**
* Positionsbestimmung am Anfang des Spiels
*/
private int ballYPos = width / 2;
private int ballXPos = height / 2;
private int paddleXpos = width / 2;
private final int paddleYpos = height - 100;
/**
* Geschwindigkeiten und Geschwindigkeitsveränderung des Balls
*/
private int ballXSpeed = 2;
private int ballYSpeed = 2;
private int paddleDeltaX = 0;
/**
* Spielstand
*/
private int score = 0;
/**
* X und Y Koordinaten, wo mit dem zeichnen begiinen werden sollen & der Abstand der Ziele von einander
*/
private final int startX = 50;
private final int startY = 20;
private final int gapX = 130;
private final int gapY = 20;
/**
* Angabe der Reihen und Spalten
*/
private int col = 0;
private int row = 0;
private final int maxRow = 5;
private final int maxCol = 5;
private int[][] bricks = new int[maxRow][maxCol];
/**
* Variablen für den Treffer
*/
public final int draw = 0;
public final int changedColor = 1;
public final int destryoed = 2;
@Override
public void start(Stage primaryStage) throws Exception {
Canvas canvas = new Canvas(width, height);
GraphicsContext bg = canvas.getGraphicsContext2D();
GraphicsContext ball = canvas.getGraphicsContext2D();
GraphicsContext paddle = canvas.getGraphicsContext2D();
GraphicsContext targets = canvas.getGraphicsContext2D();
Timeline t = new Timeline(new KeyFrame(Duration.millis(10), e -> mainGame(bg, ball, paddle, targets)));
t.setCycleCount(Timeline.INDEFINITE);
canvas.setOnMouseClicked(e -> gameStarted = true);
Scene scene = new Scene(new StackPane(canvas));
/**
* KeyHandler für das betätigen der Tasten zur Steuerung des Schlägers
*/
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case A:
case LEFT:
paddleDeltaX = -4;
break;
case D:
case RIGHT:
paddleDeltaX = 4;
break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
paddleDeltaX = 0;
}
});
primaryStage.setTitle("Breakout");
primaryStage.setScene(scene);
primaryStage.show();
t.play();
}
/**
* Erkennung der Kollision an der oberen Seite des Ziels
*
* @return True oder false, insofern eine Kollision stattfindet
*/
public boolean intersectsTargetUp() {
boolean erg = false;
if ((ballXPos + (durch / 2)) >= (col * gapX + startX) && (ballXPos + (durch / 2)) <= (col * gapX + startX) + brickW && ballYPos + durch == row * gapY + startY) {
erg = true;
}
return erg;
}
/**
* Erkennung der Kollision an der unteren Seite des Ziels
*
* @return True oder false, insofern eine Kollision stattfindet
*/
public boolean intersectsTargetDown() {
boolean erg = false;
if ((ballXPos + (durch / 2)) >= (col * gapX + startX) && (ballXPos + (durch / 2)) <= (col * gapX + startX) + brickW && ballYPos == (row * gapY + startY) + brickH) {
erg = true;
}
return erg;
}
/**
* Erkennung der Kollision an der linken Seite des Ziels
*
* @return True oder false, insofern eine Kollision stattfindet
*/
public boolean intersectsTargetLeft() {
boolean erg = false;
if (ballYPos + (durch / 2) >= (row * gapY + startY) && ballYPos + (durch / 2) <= (row * gapY + startY) + brickH && ballXPos + durch == (col * gapX + startX)) {
erg = true;
}
return erg;
}
/**
* Erkennung der Kollision an der rechten Seite des Ziels
*
* @return True oder false, insofern eine Kollision stattfindet
*/
public boolean intersectsTargetRight() {
boolean erg = false;
if (ballYPos + (durch / 2) >= (row * gapY + startY) && ballYPos + (durch / 2) <= (row * gapY + startY) + brickH && ballXPos == (col * gapX + startX) + brickW) {
erg = true;
}
return erg;
}
/**
* Hauptmethode des Spiels
*
* @param bg Hintergrund
* @param ball Ball
* @param paddle Schläger
* @param targets Ziele
*/
public void mainGame(GraphicsContext bg, GraphicsContext ball, GraphicsContext paddle, GraphicsContext targets) {
/**
* Start des Spiels nach Mausclick
*/
if (gameStarted) {
bg.setFill(Color.GRAY);
bg.fillRect(0, 0, width, height);
paddleXpos += paddleDeltaX;
ballYPos += ballYSpeed;
ballXPos += ballXSpeed;
paddle.setFill(Color.BLUE);
paddle.fillRect(paddleXpos, paddleYpos, paddleW, paddleH);
ball.setFill(Color.GREEN);
ball.fillOval(ballXPos, ballYPos, durch, durch);
targets.setFill(Color.RED);
for (row = 0; row < maxRow; row++) {
for (col = 0; col < maxCol; col++) {
if (bricks[row][col] == draw) {
targets.fillRect(col * gapX + startX, row * gapY + startY, brickW, brickH);
}
if (intersectsTargetRight() || intersectsTargetLeft()) {
ballXSpeed *= -1;
}
if (intersectsTargetDown() || intersectsTargetUp()) {
ballYSpeed *= -1;
}
if (intersectsTargetDown() || intersectsTargetLeft() || intersectsTargetRight() || intersectsTargetUp()) {
bricks[row][col] += 1;
continue;
}
if (bricks[row][col] == changedColor) {
targets.setFill(Color.YELLOW);
}
if (bricks[row][col] == destryoed) {
targets.clearRect(col * gapX + startX, row * gapY + startY, brickW, brickH);
score+=1;
}
}
}
} else {
/**
* Startbildschirm
*/
bg.setFill(Color.GRAY);
bg.fillRect(0, 0, width, height);
bg.setFont(Font.font("Impact", 130));
bg.setFill(Color.YELLOW);
bg.setTextAlign(TextAlignment.CENTER);
bg.fillText("BREAKOUT!!!", width / 2, 200);
bg.setFont(Font.font("Arial Black", 50));
bg.setFill(Color.BLACK);
bg.setTextAlign(TextAlignment.CENTER);
bg.fillText("Click to Start!", width / 2, height / 2);
bg.setFont(Font.font("Comic Sans", 45));
bg.setFill(Color.DARKRED);
bg.setTextAlign(TextAlignment.CENTER);
bg.fillText("Have fun!", width / 2, height - 200);
}
/**
* Bewegung des Schlägers
*/
if (paddleXpos < 0) {
paddleXpos = 0;
} else if (paddleXpos > width - paddleW) {
paddleXpos = width - paddleW;
}
/**
* Ballabpraller an den Rändern
*/
if (ballXPos == width - durch || ballXPos == 0) {
ballXSpeed *= -1;
}
if (ballYPos == 0) {
ballYSpeed *= -1;
}
/**
* Abbruchkriterium, wenn der Ball aus dem unteren Bildschirm hinauswandert
*/
if (ballYPos + durch > height) {
bg.setFill(Color.GRAY);
bg.fillRect(0, 0, width, height);
bg.setFont(Font.font("Arial Black", 50));
bg.setFill(Color.BLACK);
bg.setTextAlign(TextAlignment.CENTER);
bg.fillText("Game Over!", width / 2, height / 2);
bg.setFont(Font.font("Comic Sans", 45));
bg.setFill(Color.DARKRED);
bg.setTextAlign(TextAlignment.CENTER);
bg.fillText("Your score: " + score, width / 2, height - 200);
}
/**
* Ballbewegung, wenn der Ball den Schläger berührt
*/
if (ballXPos + durch / 2 >= paddleXpos && ballXPos + durch / 2 <= paddleXpos + paddleW && ballYPos + durch == paddleYpos) {
ballYSpeed *= -1;
}
}
}