Select Git revision
-
Robert Goldmann authoredRobert Goldmann authored
LevelController.java 32.60 KiB
package de.bricked.ui;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.Optional;
import java.util.Random;
import java.util.ResourceBundle;
import de.bricked.game.Game;
import de.bricked.game.GameState;
import de.bricked.game.HitLocation;
import de.bricked.game.balls.Ball;
import de.bricked.game.balls.BallType;
import de.bricked.game.board.Board;
import de.bricked.game.bricks.Brick;
import de.bricked.game.bricks.BrickType;
import de.bricked.game.paddle.Paddle;
import de.bricked.game.paddle.PaddleSize;
import de.bricked.game.powerups.PowerUp;
import de.bricked.game.powerups.PowerUpType;
import de.bricked.game.sound.SoundType;
import de.bricked.utils.CountdownTimer;
import fontAwesome.FontIcon;
import fontAwesome.FontIconType;
import javafx.animation.AnimationTimer;
import javafx.animation.FadeTransition;
import javafx.animation.ParallelTransition;
import javafx.animation.TranslateTransition;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.effect.Lighting;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Duration;
import kuusisto.tinysound.TinySound;
import logger.LogLevel;
import logger.Logger;
import tools.AlertGenerator;
import tools.Worker;
public class LevelController
{
@FXML private AnchorPane anchorPane;
@FXML private Label labelLevelName;
@FXML private Label labelAuthor;
@FXML private Label labelLevelPack;
@FXML private Label labelPoints;
@FXML private Label labelBlocksRemaining;
@FXML private Label labelMultiplicator;
@FXML private AnchorPane anchorPaneGame;
@FXML private Button buttonBack;
@FXML private VBox vboxPowerUps;
@FXML private VBox vboxLives;
@FXML private Label labelFPS;
public Stage stage;
public Image icon = new Image("de/bricked/resources/icon.png");
public final ResourceBundle bundle = ResourceBundle.getBundle("de/bricked/main/", Locale.GERMANY);
private LevelSelectController levelSelectController;
private Game game;
private static GridPane grid;
private AnimationTimer timer;
private double gamePaneWidth;
private double gamePaneHeight;
private final int TARGET_FPS = 60;
private final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
private final static double BRICK_FADE_DURATION = 300.0;
private int fps;
private Paddle paddle;
private GameState gameState;
private ImageView labelPaddle;
private StackPane stackPaneBall;
private ChangeListener<Number> heightListener;
private ChangeListener<Number> widthListener;
private double oldMousePosition;
private static ArrayList<Label> brickLabels;
private ArrayList<Label> movingPowerUps;
private ArrayList<CountdownTimer> timedPowerUps;
private long previousTime = 0;
private float secondsElapsedSinceLastFpsUpdate = 0f;
private void startGame()
{
resetPowerUps();
anchorPaneGame.heightProperty().removeListener(heightListener);
anchorPaneGame.widthProperty().removeListener(widthListener);
double yPosition = (gamePaneHeight / Board.HEIGHT) * (20);
labelMultiplicator.setLayoutX(0);
labelMultiplicator.setLayoutY(0);
labelMultiplicator.setTranslateX((gamePaneWidth - 100) / 2);
labelMultiplicator.setTranslateY(yPosition);
// start random into left or right direction
int random = new Random().nextInt(2);
if(random == 0)
{
game.getBall().startBallToRight();
}
else
{
game.getBall().startBallToLeft();
}
timer.start();
Logger.log(LogLevel.INFO, "ball start");
gameState = GameState.RUNNING;
}
public void init(Stage stage, LevelSelectController levelSelectController, Game game)
{
this.stage = stage;
this.levelSelectController = levelSelectController;
this.game = game;
game.setBoard(new Board(game));
game.setLevelController(this);
anchorPane.setStyle("-fx-base: " + bundle.getString("color.background") + ";");
buttonBack.setStyle("-fx-base: " + bundle.getString("color.button.light"));
anchorPaneGame.setStyle("-fx-background-color: " + bundle.getString("color.default"));
labelMultiplicator.setStyle("-fx-text-fill: #000000;");
anchorPaneGame.setCursor(Cursor.NONE);
anchorPaneGame.setOnMouseClicked(new EventHandler<MouseEvent>()
{
@Override
public void handle(MouseEvent event)
{
if(gameState.equals(GameState.WAITING))
{
startGame();
}
event.consume();
anchorPaneGame.requestFocus();
}
});
anchorPane.setOnKeyReleased(new EventHandler<KeyEvent>()
{
@Override
public void handle(KeyEvent event)
{
if(event.getCode().toString().equals(bundle.getString("shortcut.debug.console")))
{
showCommandLine();
Logger.log(LogLevel.INFO, "openend debug console");
event.consume();
return;
}
if(event.getCode().toString().equals("SPACE"))
{
if(gameState.equals(GameState.WAITING))
{
startGame();
}
event.consume();
anchorPaneGame.requestFocus();
return;
}
if(event.getCode().toString().equals("ESCAPE"))
{
if(gameState.equals(GameState.STOPPED))
{
back();
event.consume();
return;
}
pause();
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Close Level?");
alert.setHeaderText("");
alert.setContentText("Do you really want to go back?");
Stage dialogStage = (Stage) alert.getDialogPane().getScene().getWindow();
dialogStage.getIcons().add(icon);
dialogStage.initOwner(stage);
Optional<ButtonType> result = alert.showAndWait();
if(result.get() == ButtonType.OK)
{
back();
event.consume();
}
else
{
restart();
event.consume();
}
}
//pause
if(event.getCode().toString().equals("P"))
{
if(gameState.equals(GameState.RUNNING))
{
pause();
event.consume();
return;
}
if(gameState.equals(GameState.PAUSED))
{
restart();
event.consume();
return;
}
}
}
});
anchorPane.setOnKeyPressed(new EventHandler<KeyEvent>()
{
@Override
public void handle(KeyEvent event)
{
if(gameState.equals(GameState.RUNNING))
{
if(event.getCode().toString().equals("RIGHT"))
{
movePaddleRight();
}
if(event.getCode().toString().equals("LEFT"))
{
movePaddleLeft();
}
}
}
});
anchorPane.setOnMouseMoved(new EventHandler<MouseEvent>()
{
@Override
public void handle(MouseEvent event)
{
if(gameState.equals(GameState.RUNNING))
{
// --> direct follow mouse
double newPaddlePosition = event.getSceneX() - paddle.getWidth() / 2;
// move left
if(newPaddlePosition < oldMousePosition)
{
if(newPaddlePosition > 0)
{
labelPaddle.setTranslateX(newPaddlePosition);
}
else
{
labelPaddle.setTranslateX(0);
}
}
// move right
else
{
if((newPaddlePosition + paddle.getWidth()) < gamePaneWidth)
{
labelPaddle.setTranslateX(newPaddlePosition);
}
else
{
labelPaddle.setTranslateX(gamePaneWidth - paddle.getWidth());
}
}
oldMousePosition = labelPaddle.getScene().getX();
}
}
});
stage.setOnCloseRequest(new EventHandler<WindowEvent>()
{
public void handle(WindowEvent event)
{
if(timer != null)
{
timer.stop();
}
TinySound.shutdown();
Worker.shutdown();
Platform.exit();
System.exit(0);
}
});
FontIcon iconBack = new FontIcon(FontIconType.ARROW_LEFT);
iconBack.setSize(18);
buttonBack.setText("");
buttonBack.setGraphic(iconBack);
vboxPowerUps.setStyle("-fx-border-color: #000000; -fx-border-width: 2px; -fx-background-color: #F4F4F4");
vboxPowerUps.setPadding(new Insets(3));
vboxPowerUps.setAlignment(Pos.TOP_CENTER);
vboxPowerUps.setSpacing(7);
vboxLives.setStyle("-fx-border-color: #000000; -fx-border-width: 2px; -fx-background-color: #F4F4F4");
vboxLives.setPadding(new Insets(3));
vboxLives.setAlignment(Pos.BOTTOM_CENTER);
vboxLives.setSpacing(9);
anchorPaneGame.setPadding(new Insets(0));
labelLevelPack.setText(game.getLevelPack().getPackageName());
labelAuthor.setText("by " + game.getLevel().getAuthor());
labelLevelName.setText(game.getLevel().getName() + " (" + game.getLevel().getPosition() + "/" + game.getLevelPack().getLevels().size() + ")");
labelBlocksRemaining.setText(game.getBoard().getNumberOfRemainingBricks() + " Bricks remaining");
game.setLivesRemaining(game.getLevel().getStartLives());
gamePaneWidth = game.getSettings().getGameSize().getWidth() - 100;
gamePaneHeight = game.getSettings().getGameSize().getHeight() - 150;
grid = new GridPane();
grid.setGridLinesVisible(false);
grid.setStyle("-fx-border-color: #000000; -fx-border-width: 2px;");
grid.setHgap(0);
grid.setVgap(0);
anchorPaneGame.getChildren().add(grid);
AnchorPane.setTopAnchor(grid, 0.0);
AnchorPane.setRightAnchor(grid, 0.0);
AnchorPane.setBottomAnchor(grid, 0.0);
AnchorPane.setLeftAnchor(grid, 0.0);
redraw();
refreshLiveCounter();
initPaddle(game.getLevel().getInitPadSize());
oldMousePosition = labelPaddle.getScene().getX() - paddle.getWidth() / 2;
heightListener = new ChangeListener<Number>()
{
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue)
{
initBall(BallType.NORMAL);
initTimer();
gamePaneHeight = newValue.doubleValue();
}
};
widthListener = new ChangeListener<Number>()
{
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue)
{
gamePaneWidth = newValue.doubleValue();
}
};
anchorPaneGame.heightProperty().addListener(heightListener);
anchorPaneGame.widthProperty().addListener(widthListener);
anchorPaneGame.requestFocus();
showLabelFPS(levelSelectController.controller.controller.getCommandLine().getBundle().isShowFPS());
labelFPS.setStyle("-fx-text-fill: #FF0000");
resetMultiplicator();
resetPowerUps();
gameState = GameState.WAITING;
}
public Paddle getPaddle()
{
return paddle;
}
public ImageView getLabelPaddle()
{
return labelPaddle;
}
private void initTimer()
{
previousTime = 0;
secondsElapsedSinceLastFpsUpdate = 0f;
fps = 0;
timer = new AnimationTimer()
{
@Override
public void handle(long currentTime)
{
if(previousTime == 0)
{
previousTime = currentTime;
return;
}
float secondsElapsed = currentTime - previousTime;
previousTime = currentTime;
double delta = secondsElapsed / ((double)OPTIMAL_TIME);
secondsElapsedSinceLastFpsUpdate += secondsElapsed;
fps++;
if(secondsElapsedSinceLastFpsUpdate >= 1000000000)
{
labelFPS.setText(String.valueOf(fps));
Logger.log(LogLevel.DEBUG, "current FPS: " + fps);
secondsElapsedSinceLastFpsUpdate = 0;
fps = 0;
}
// update ball location
stackPaneBall.setTranslateX(stackPaneBall.getTranslateX() + game.getBall().getDirection().getX() * delta);
stackPaneBall.setTranslateY(stackPaneBall.getTranslateY() + game.getBall().getDirection().getY() * delta);
// hit detection
HitLocation hitLocation = game.hitsWall(gamePaneWidth, gamePaneHeight, stackPaneBall.getLayoutX(), stackPaneBall.getLayoutY(), stackPaneBall.getTranslateX(), stackPaneBall.getTranslateY(), game.getBall().getDirection());
Point2D ballPosition = new Point2D(stackPaneBall.getLayoutX() + stackPaneBall.getTranslateX(), stackPaneBall.getLayoutY() + stackPaneBall.getTranslateY());
Point2D paddlePosition = new Point2D(labelPaddle.getLayoutX() + labelPaddle.getTranslateX(), labelPaddle.getLayoutY() + labelPaddle.getTranslateY());
// if ball collides with border then brick collisions are irrelevant
if(hitLocation != null)
{
resetMultiplicator();
if(hitLocation.equals(HitLocation.LIFE_LOST))
{
game.setLivesRemaining(game.getLivesRemaining() - 1);
Logger.log(LogLevel.DEBUG, "Life lost (" + game.getLivesRemaining() + " lives remaining)");
refreshLiveCounter();
resetPowerUps();
if(game.getLivesRemaining() <= 0)
{
// game over
gameState = GameState.STOPPED;
timer.stop();
game.getSoundHandler().play(SoundType.GAME_OVER);
Platform.runLater(() -> {
AlertGenerator.showAlert(Alert.AlertType.INFORMATION, "Game Over", "", "Youe have no lives left", icon, stage, bundle.getString("color.background"), false);
});
}
else
{
gameState = GameState.WAITING;
timer.stop();
game.getSoundHandler().play(SoundType.LIFE_LOST);
// reset paddle and ball
initPaddle(game.getLevel().getInitPadSize());
initBall(BallType.NORMAL);
initTimer();
}
}
else
{
game.getBall().setDirection(game.reflectBall(hitLocation, game.getBall().getDirection()));
game.getSoundHandler().play(SoundType.HIT_WALL);
switch(hitLocation)
{
case BOTTOM:
stackPaneBall.setTranslateX(stackPaneBall.getTranslateX());
stackPaneBall.setTranslateY(1);
break;
case RIGHT:
stackPaneBall.setTranslateX(1);
stackPaneBall.setTranslateY(stackPaneBall.getTranslateY());
break;
case LEFT:
stackPaneBall.setTranslateX(gamePaneWidth - game.getBall().getBallRadius() * 2 - 1);
stackPaneBall.setTranslateY(stackPaneBall.getTranslateY());
break;
case CORNER:
if(ballPosition.getX() + game.getBall().getBallRadius() > gamePaneWidth / 2)
{
// ball is in top right corner
stackPaneBall.setTranslateX(gamePaneWidth - game.getBall().getBallRadius() * 2 - 1);
stackPaneBall.setTranslateY(1);
break;
}
else
{
// ball is in top left corner
stackPaneBall.setTranslateX(1);
stackPaneBall.setTranslateY(1);
break;
}
default:
break;
}
}
}
// ball doesn't collide with border --> check collision with paddle
else
{
hitLocation = game.collides(ballPosition, paddlePosition, paddle.getWidth(), paddle.getHeight(), true);
if(hitLocation != null && (hitLocation.equals(HitLocation.PADDLE) || hitLocation.equals(HitLocation.CORNER)))
{
game.getBall().setDirection(game.reflectOnPaddle(game.getBall().getDirection(), game.getDistanceToPaddleCenter(ballPosition, paddlePosition, paddle.getWidth())));
correctBallPosition(hitLocation, ballPosition, paddlePosition, paddle.getWidth(), paddle.getHeight());
resetMultiplicator();
game.getSoundHandler().play(SoundType.HIT_PADDLE);
}
// ball doesn't collide with paddle --> check collision with bricks
else
{
if(game.getBall().getDirection().getX() > 0)
{
for(int i = 0; i < Board.HEIGHT; i++)
{
for(int k = 0; k < Board.WIDTH; k++)
{
brickCollisionDetection(i, k, ballPosition);
}
}
}
else
{
for(int i = (int)Board.HEIGHT - 1; i >= 0; i--)
{
for(int k = (int)Board.WIDTH - 1; k >= 0; k--)
{
brickCollisionDetection(i, k, ballPosition);
}
}
}
}
}
// move powerups
movePowerUps();
}
};
}
private void pause()
{
gameState = GameState.PAUSED;
timer.stop();
anchorPaneGame.setOpacity(0.5);
Text t = new Text("PAUSED");
t.setFont(new Font(40));
new Scene(new Group(t));
t.applyCss();
Label labelPause = new Label("PAUSED");
labelPause.setStyle("-fx-font-weight: bold; -fx-font-size: 40;");
labelPause.setTranslateX(((gamePaneWidth - t.getLayoutBounds().getWidth() + 10) / 2) + 22);
labelPause.setTranslateY(((gamePaneHeight - t.getLayoutBounds().getHeight()) / 2) + 125);
anchorPane.getChildren().add(labelPause);
//pause all timedPowerUps
for(CountdownTimer currentTimer : timedPowerUps)
{
currentTimer.stop();
}
}
private void restart()
{
gameState = GameState.RUNNING;
previousTime = 0;
secondsElapsedSinceLastFpsUpdate = 0f;
fps = 0;
anchorPaneGame.setOpacity(1.0);
anchorPane.getChildren().remove(anchorPane.getChildren().size() - 1);
//restart all timedPowerUps
for(CountdownTimer currentTimer : timedPowerUps)
{
currentTimer.start();
}
timer.start();
}
public void correctBallPosition(HitLocation hitLocation, Point2D ballPosition, Point2D brickPosition, double brickWidth, double brickHeight)
{
// correct ball position if inside brick
Point2D correctedBallPosition = game.getCorrectedBallPosition(hitLocation, ballPosition, brickPosition, brickWidth, brickHeight);
stackPaneBall.setTranslateX(correctedBallPosition.getX() - stackPaneBall.getLayoutX());
stackPaneBall.setTranslateY(correctedBallPosition.getY() - stackPaneBall.getLayoutY());
}
public void redraw()
{
grid.getChildren().clear();
brickLabels = new ArrayList<>();
grid.getColumnConstraints().clear();
double xPercentage = 1.0 / Board.WIDTH;
for(int i = 0; i < Board.WIDTH; i++)
{
ColumnConstraints c = new ColumnConstraints();
c.setPercentWidth(xPercentage * 100);
grid.getColumnConstraints().add(c);
}
grid.getRowConstraints().clear();
double yPercentage = 1.0 / Board.HEIGHT;
for(int i = 0; i < Board.HEIGHT; i++)
{
RowConstraints c = new RowConstraints();
c.setPercentHeight(yPercentage * 100);
grid.getRowConstraints().add(c);
}
for(int i = 0; i < Board.HEIGHT; i++)
{
for(int k = 0; k < Board.WIDTH; k++)
{
Brick currentBrick = game.getBoard().getBricks().get(i).get(k);
Label labelBrick = new Label();
labelBrick.setStyle("-fx-background-image: url(\"de/bricked/resources/textures/bricks/" + currentBrick.getCurrentTextureID() + ".png\");" + "-fx-background-position: center center;" + "-fx-background-repeat: no-repeat;" + "-fx-background-size: cover");
labelBrick.setAlignment(Pos.CENTER);
labelBrick.prefWidthProperty().bind(grid.getColumnConstraints().get(0).percentWidthProperty().multiply(gamePaneWidth));
labelBrick.prefHeightProperty().bind(grid.getRowConstraints().get(0).percentHeightProperty().multiply(gamePaneHeight));
brickLabels.add(labelBrick);
grid.add(labelBrick, k, i);
}
}
}
public static void redrawBrick(int column, int row, Brick brick, boolean fade)
{
int id = row * (int)Board.WIDTH + column;
Label labelBrick = brickLabels.get(id);
if(fade)
{
FadeTransition ft = new FadeTransition(Duration.millis(BRICK_FADE_DURATION), labelBrick);
ft.setFromValue(1.0);
ft.setToValue(0.0);
ft.setCycleCount(1);
ft.setAutoReverse(false);
ft.setOnFinished(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
labelBrick.setStyle("-fx-background-image: url(\"de/bricked/resources/textures/bricks/" + brick.getCurrentTextureID() + ".png\");" + "-fx-background-position: center center;" + "-fx-background-repeat: no-repeat;" + "-fx-background-size: cover");
}
});
ft.play();
}
else
{
labelBrick.setStyle("-fx-background-image: url(\"de/bricked/resources/textures/bricks/" + brick.getCurrentTextureID() + ".png\");" + "-fx-background-position: center center;" + "-fx-background-repeat: no-repeat;" + "-fx-background-size: cover");
}
}
public void refreshLiveCounter()
{
vboxLives.getChildren().clear();
for(int i = 0; i < game.getLivesRemaining() - 1; i++)
{
ImageView iv = new ImageView(new Image("de/bricked/resources/textures/paddle/paddle-small.png"));
iv.setFitWidth(70);
iv.setFitHeight(120 / game.getMaxLives());
vboxLives.getChildren().add(iv);
}
}
public void initPaddle(PaddleSize paddleSize)
{
anchorPaneGame.getChildren().remove(labelPaddle);
paddle = new Paddle(paddleSize, gamePaneHeight / Board.HEIGHT, gamePaneWidth);
labelPaddle = new ImageView(new Image("de/bricked/resources/textures/paddle/" + paddle.getPaddleSize().getTextureID() + ".png"));
labelPaddle.setFitWidth(paddle.getWidth());
labelPaddle.setFitHeight(paddle.getHeight());
labelPaddle.setTranslateX(gamePaneWidth / 2 - paddle.getWidth() / 2);
anchorPaneGame.getChildren().add(labelPaddle);
AnchorPane.setBottomAnchor(labelPaddle, paddle.getHeight());
}
private void initBall(BallType ballType)
{
anchorPaneGame.getChildren().remove(stackPaneBall);
game.setBall(new Ball(ballType));
final Circle circle = new Circle(game.getBall().getBallRadius(), Color.web(game.getBall().getType().getColor()));
circle.setEffect(new Lighting());
stackPaneBall = new StackPane();
stackPaneBall.getChildren().addAll(circle);
stackPaneBall.setTranslateX(gamePaneWidth / 2 - game.getBall().getBallRadius());
stackPaneBall.setTranslateY(anchorPaneGame.getHeight() - paddle.getHeight() * 2 - game.getBall().getBallRadius() * 2);
anchorPaneGame.getChildren().add(stackPaneBall);
}
private void resetMultiplicator()
{
game.applyMultiplicator();
labelPoints.setText(String.valueOf(game.getTotalPoints()));
labelMultiplicator.setText("");
if(game.getMultiplicator() > 1)
{
showAnimatedPoints(20, 8, game.getPointsSinceLastMultiplicatorReset() * game.getMultiplicator(), 25, true);
}
game.resetPointsSinceLastMultiplicatorReset();
game.resetMultiplicator();
}
public void increaseMultiplicator(int points)
{
game.increaseMultiplicator();
game.increasePointsSinceLastMultiplicatorReset(points);
if(game.getMultiplicator() > 1)
{
labelMultiplicator.setText("x" + game.getMultiplicator());
}
}
private void movePaddleLeft()
{
if(labelPaddle.getLayoutX() + labelPaddle.getTranslateX() - paddle.getSpeed() > 0)
{
labelPaddle.setTranslateX(labelPaddle.getTranslateX() - paddle.getSpeed());
}
else
{
labelPaddle.setTranslateX(0);
}
}
private void movePaddleRight()
{
if(labelPaddle.getLayoutX() + labelPaddle.getTranslateX() + paddle.getSpeed() + paddle.getWidth() < gamePaneWidth)
{
labelPaddle.setTranslateX(labelPaddle.getTranslateX() + paddle.getSpeed());
}
else
{
labelPaddle.setTranslateX(anchorPaneGame.getWidth() - paddle.getWidth());
}
}
private void brickCollisionDetection(int i, int k, Point2D ballPosition)
{
Brick currentBrick = game.getBoard().getBricks().get(i).get(k);
if(!currentBrick.getType().equals(BrickType.AIR))
{
Label stackPaneBrick = (Label)grid.getChildren().get(i * (int)Board.WIDTH + k);
Point2D brickPosition = new Point2D(stackPaneBrick.getLayoutX() + stackPaneBrick.getTranslateX(), stackPaneBrick.getLayoutY() + stackPaneBrick.getTranslateY());
HitLocation hitLocation = game.collides(ballPosition, brickPosition, stackPaneBrick.getWidth(), stackPaneBrick.getHeight(), false);
if(hitLocation != null)
{
if(!game.getBall().getType().equals(BallType.NO_COLLISION))
{
game.getBall().setDirection(game.reflectBall(hitLocation, game.getBall().getDirection()));
correctBallPosition(hitLocation, ballPosition, brickPosition, stackPaneBrick.getWidth(), stackPaneBrick.getHeight());
}
int points = game.getBoard().hitBrick(i, k, game.getBall());
// brick has been destroyed
if(points > 0)
{
game.setTotalPoints(game.getTotalPoints() + points);
labelPoints.setText(String.valueOf(game.getTotalPoints()));
labelBlocksRemaining.setText(game.getBoard().getNumberOfRemainingBricks() + " Bricks remaining");
}
if(game.getBoard().getNumberOfRemainingBricks() == 0)
{
// level done
resetPowerUps();
gameState = GameState.STOPPED;
resetMultiplicator();
timer.stop();
game.getSoundHandler().play(SoundType.FINISHED_LEVEL);
Platform.runLater(() -> {
AlertGenerator.showAlert(Alert.AlertType.INFORMATION, "Congratulations!", "", "You finished Level \"" + game.getLevel().getName() + "\" with " + game.getTotalPoints() + " Points", icon, stage, bundle.getString("color.background"), false);
});
}
}
}
}
public void showAnimatedPoints(int row, int col, int points, double fontSize, boolean centerInPane)
{
Text t = new Text("+" + points);
t.setFont(new Font(fontSize));
new Scene(new Group(t));
t.applyCss();
double xPosition = (gamePaneWidth / Board.WIDTH) * (col);
if(centerInPane)
{
xPosition = (gamePaneWidth - t.getLayoutBounds().getWidth() + 10) / 2;
}
double yPosition = (gamePaneHeight / Board.HEIGHT) * (row);
Label labelNotification = new Label("+" + points);
labelNotification.setTranslateX(xPosition);
labelNotification.setTranslateY(yPosition);
labelNotification.setStyle("-fx-font-weight: bold; -fx-font-size: " + fontSize + "; -fx-text-fill: #000000;");
labelNotification.setAlignment(Pos.CENTER);
labelNotification.setPrefWidth(t.getLayoutBounds().getWidth() + 10);
labelNotification.setPrefHeight(gamePaneHeight / Board.HEIGHT);
anchorPaneGame.getChildren().add(labelNotification);
FadeTransition fadeTransition = new FadeTransition(Duration.millis(1200), labelNotification);
fadeTransition.setFromValue(1.0);
fadeTransition.setToValue(0.0);
fadeTransition.setCycleCount(1);
fadeTransition.setAutoReverse(false);
TranslateTransition translateTransition = new TranslateTransition(Duration.millis(1200), labelNotification);
translateTransition.setFromY(yPosition);
translateTransition.setToY(yPosition - (gamePaneHeight / Board.HEIGHT));
translateTransition.setCycleCount(1);
translateTransition.setAutoReverse(false);
ParallelTransition parallelTransition = new ParallelTransition();
parallelTransition.getChildren().addAll(fadeTransition, translateTransition);
parallelTransition.setCycleCount(1);
parallelTransition.setOnFinished(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
anchorPaneGame.getChildren().remove(labelNotification);
}
});
parallelTransition.play();
}
public void addMovingPowerUp(int row, int col, PowerUp powerUp)
{
Label labelPowerUp = new Label();
labelPowerUp.setStyle("-fx-background-image: url(\"de/bricked/resources/textures/powerups/" + powerUp.getID() + ".png\");" + "-fx-background-position: center center;" + "-fx-background-repeat: no-repeat;" + "-fx-background-size: cover");
labelPowerUp.setAlignment(Pos.CENTER);
labelPowerUp.setUserData(powerUp);
labelPowerUp.setPrefWidth(gamePaneWidth / Board.WIDTH);
labelPowerUp.setPrefHeight(gamePaneHeight / Board.HEIGHT);
anchorPaneGame.getChildren().add(labelPowerUp);
labelPowerUp.setTranslateX(col * (gamePaneWidth / Board.WIDTH));
labelPowerUp.setTranslateY(row * (gamePaneHeight / Board.HEIGHT));
movingPowerUps.add(labelPowerUp);
}
private void movePowerUps()
{
for(Iterator<Label> iterator = movingPowerUps.iterator(); iterator.hasNext();)
{
Label currentLabel = iterator.next();
PowerUp currentPowerUp = (PowerUp)currentLabel.getUserData();
currentLabel.setTranslateY(currentLabel.getTranslateY() + currentPowerUp.getSpeed());
// check collision with paddle
Point2D labelPosition = new Point2D(currentLabel.getTranslateX(), currentLabel.getTranslateY());
Point2D paddlePosition = new Point2D(labelPaddle.getLayoutX() + labelPaddle.getTranslateX(), labelPaddle.getLayoutY() + labelPaddle.getTranslateY());
HitLocation hitLocation = game.collides(labelPosition, paddlePosition, paddle.getWidth(), paddle.getHeight(), true);
if(hitLocation != null && (hitLocation.equals(HitLocation.PADDLE) || hitLocation.equals(HitLocation.CORNER)))
{
Logger.log(LogLevel.DEBUG, "Collected PowerUp with ID = " + currentPowerUp.getID());
if(!currentPowerUp.isPermanent())
{
addTimedPowerUp(currentPowerUp);
}
currentPowerUp.activate(this, game);
anchorPaneGame.getChildren().remove(currentLabel);
iterator.remove();
continue;
}
if(currentLabel.getTranslateY() + currentLabel.getHeight() >= gamePaneHeight)
{
// power up reached bottom wall
anchorPaneGame.getChildren().remove(currentLabel);
iterator.remove();
}
}
}
private void clearMovingPowerUps()
{
if(movingPowerUps != null)
{
for(Label currentLabel : movingPowerUps)
{
anchorPaneGame.getChildren().remove(currentLabel);
}
}
}
private void addTimedPowerUp(PowerUp powerUp)
{
boolean alreadyActivated = false;
for(CountdownTimer currentTimer : timedPowerUps)
{
PowerUp currentPowerUp = (PowerUp)currentTimer.getHBox().getUserData();
if(currentPowerUp.getID() == powerUp.getID())
{
alreadyActivated = true;
currentTimer.addSecondsToTimer(powerUp.getDurationInSeconds());
break;
}
}
if(!alreadyActivated)
{
deactivateAllContraryPowerUps(powerUp);
HBox hbox = new HBox();
Label labelIcon = new Label();
labelIcon.setStyle("-fx-background-image: url(\"de/bricked/resources/textures/powerups/" + powerUp.getID() + ".png\");" + "-fx-background-position: center center;" + "-fx-background-repeat: no-repeat;" + "-fx-background-size: contain;");
labelIcon.setPrefWidth(35);
labelIcon.setPrefHeight(20);
Label labelSeconds = new Label(String.valueOf(powerUp.getDurationInSeconds()));
labelSeconds.setStyle("-fx-font-size: 16;" + "-fx-font-weight: bold; -fx-text-fill: #000000;");
hbox.getChildren().add(labelIcon);
hbox.getChildren().add(labelSeconds);
HBox.setHgrow(labelSeconds, Priority.ALWAYS);
HBox.setMargin(labelSeconds, new Insets(0, 0, 0, 7));
hbox.setAlignment(Pos.CENTER_LEFT);
hbox.setUserData(powerUp);
vboxPowerUps.getChildren().add(hbox);
timedPowerUps.add(new CountdownTimer(powerUp.getDurationInSeconds(), hbox, this));
}
}
private void resetPowerUps()
{
clearMovingPowerUps();
movingPowerUps = new ArrayList<>();
timedPowerUps = new ArrayList<>();
vboxPowerUps.getChildren().clear();
}
public void deactivateAllContraryPowerUps(PowerUp powerUp)
{
ArrayList<Integer> deactiveIDs = PowerUpType.valueOf(powerUp.getID()).getDeactivatesPowerUpIDs();
if(deactiveIDs != null)
{
for(int currentInt : deactiveIDs)
{
for(CountdownTimer currentTimer : timedPowerUps)
{
PowerUp currentPowerUp = (PowerUp)currentTimer.getHBox().getUserData();
if(currentPowerUp.getID() == currentInt)
{
currentTimer.stop();
deactivatePowerUp(currentTimer, currentTimer.getHBox());
break;
}
}
}
}
}
public void deactivatePowerUp(CountdownTimer timer, HBox hbox)
{
PowerUp powerUp = (PowerUp)hbox.getUserData();
vboxPowerUps.getChildren().remove(hbox);
timedPowerUps.remove(timer);
powerUp.deactivate(this, game);
}
public void showLabelFPS(boolean value)
{
labelFPS.setVisible(value);
}
public void showCommandLine()
{
try
{
levelSelectController.controller.controller.getCommandLine().showCommandLine("Debug Console", 400, 250, 400, 200, -1, -1, true);
}
catch(IOException e)
{
// TODO: errorhandling
Logger.log(LogLevel.ERROR, Logger.exceptionToString(e));
}
}
public void back()
{
if(timer != null)
{
timer.stop();
}
stage.close();
levelSelectController.stage.show();
game.setTotalPoints(0);
game.resetMultiplicator();
game.resetPointsSinceLastMultiplicatorReset();
game.setBoard(null);
game.setLevelController(null);
game.setMovingPowerUps(new ArrayList<>());
game.getSoundHandler().stopAll();
anchorPaneGame.requestFocus();
}
/*
* PowerUP-Functions
*/
public void changeBall(Ball newBall)
{
double translateX = stackPaneBall.getTranslateX();
double translateY = stackPaneBall.getTranslateY();
Point2D direction = game.getBall().getDirection();
game.setBall(newBall);
initBall(game.getBall().getType());
stackPaneBall.setTranslateX(translateX);
stackPaneBall.setTranslateY(translateY);
game.getBall().setDirection(game.getNewSpeedDirection(direction, newBall.getType().getSpeedFactor()));
}
}