blob: d4b56e25c015a35c2f1e07fad01b7ecabe5067cf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package brickbreaker;
import java.util.ArrayList;
import java.util.Iterator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.VPos;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.util.Duration;
import brickbreaker.Main.MainFrame;
public class Level extends Parent {
private static final double MOB_SCALING = 1.5f;
private static final MainFrame mainFrame = Main.getMainFrame();
private ArrayList<Brick> bricks;
private int brickCount;
private ArrayList<Brick> fadeBricks;
private ArrayList<Bonus> bonuses;
private Group group;
private ArrayList<Bonus> lives;
private int catchedBonus;
// States
// 0 - starting level
// 1 - ball is catched
// 2 - playing
// 3 - game over
private static final int STARTING_LEVEL = 0;
private static final int BALL_CATCHED = 1;
private static final int PLAYING = 2;
private static final int GAME_OVER = 3;
private int state;
private int batDirection;
private double ballDirX;
private double ballDirY;
private int levelNumber;
private Bat bat;
private Ball ball;
private Text roundCaption;
private Text round;
private Text scoreCaption;
private Text score;
private Text livesCaption;
private ImageView message;
private Timeline startingTimeline;
private Timeline timeline;
private Group infoPanel;
public Level(int levelNumber) {
group = new Group();
getChildren().add(group);
initContent(levelNumber);
}
private void initStartingTimeline() {
startingTimeline = new Timeline();
KeyFrame kf1 = new KeyFrame(Duration.millis(500), new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
message.setVisible(true);
state = STARTING_LEVEL;
bat.setVisible(false);
ball.setVisible(false);
}
}, new KeyValue(message.opacityProperty(), 0));
KeyFrame kf2 = new KeyFrame(Duration.millis(1500), new KeyValue(message.opacityProperty(), 1));
KeyFrame kf3 = new KeyFrame(Duration.millis(3000), new KeyValue(message.opacityProperty(), 1));
KeyFrame kf4 = new KeyFrame(Duration.millis(4000), new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
message.setVisible(false);
bat.setTranslateX((Config.FIELD_WIDTH - bat.getWidth()) / 2.0);
ball.setTranslateX((Config.FIELD_WIDTH - ball.getDiameter()) / 2.0);
ball.setTranslateY(Config.BAT_Y - ball.getDiameter());
ballDirX = (Utils.random(2) * 2 - 1) * Config.BALL_MIN_COORD_SPEED;
ballDirY = -Config.BALL_MIN_SPEED;
bat.setVisible(true);
ball.setVisible(true);
state = BALL_CATCHED;
}
}, new KeyValue(message.opacityProperty(), 0));
startingTimeline.getKeyFrames().addAll(kf1, kf2, kf3, kf4);
}
private void initTimeline() {
timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
KeyFrame kf = new KeyFrame(Config.ANIMATION_TIME, new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
// Process fadeBricks
Iterator<Brick> brickIterator = fadeBricks.iterator();
while (brickIterator.hasNext()) {
Brick brick = brickIterator.next();
brick.setOpacity(brick.getOpacity() - 0.1);
if (brick.getOpacity() <= 0) {
brick.setVisible(false);
brickIterator.remove();
}
}
// Move bat if needed
if (batDirection != 0 && state != STARTING_LEVEL) {
moveBat(bat.getTranslateX() + batDirection);
}
// Process bonuses
Iterator<Bonus> bonusIterator = bonuses.iterator();
while (bonusIterator.hasNext()) {
Bonus bonus = bonusIterator.next();
if (bonus.getTranslateY() > Config.SCREEN_HEIGHT) {
bonus.setVisible(false);
bonusIterator.remove();
group.getChildren().remove(bonus);
} else {
bonus.setTranslateY(bonus.getTranslateY() + Config.BONUS_SPEED);
if (bonus.getTranslateX() + bonus.getWidth() > bat.getTranslateX() &&
bonus.getTranslateX() < bat.getTranslateX() + bat.getWidth() &&
bonus.getTranslateY() + bonus.getHeight() > bat.getTranslateY() &&
bonus.getTranslateY() < bat.getTranslateY() + bat.getHeight()) {
// Bonus is catched
updateScore(100);
catchedBonus = bonus.getType();
bonus.setVisible(false);
bonusIterator.remove();
group.getChildren().remove(bonus);
if (bonus.getType() == Bonus.TYPE_SLOW) {
ballDirX /= 1.5;
ballDirY /= 1.5;
correctBallSpeed();
} else if (bonus.getType() == Bonus.TYPE_FAST) {
ballDirX *= 1.5;
ballDirY *= 1.5;
correctBallSpeed();
} else if (bonus.getType() == Bonus.TYPE_GROW_BAT) {
if (bat.getSize() < Bat.MAX_SIZE) {
bat.changeSize(bat.getSize() + 1);
if (bat.getTranslateX() + bat.getWidth() > Config.FIELD_WIDTH) {
bat.setTranslateX(Config.FIELD_WIDTH - bat.getWidth());
}
}
} else if (bonus.getType() == Bonus.TYPE_REDUCE_BAT) {
if (bat.getSize() > 0) {
int oldWidth = bat.getWidth();
bat.changeSize(bat.getSize() - 1);
bat.setTranslateX(bat.getTranslateX() + ((oldWidth - bat.getWidth()) / 2));
}
} else if (bonus.getType() == Bonus.TYPE_GROW_BALL) {
if (ball.getSize() < Ball.MAX_SIZE) {
ball.changeSize(ball.getSize() + 1);
if (state == BALL_CATCHED) {
ball.setTranslateY(Config.BAT_Y - ball.getDiameter());
}
}
} else if (bonus.getType() == Bonus.TYPE_REDUCE_BALL) {
if (ball.getSize() > 0) {
ball.changeSize(ball.getSize() - 1);
if (state == BALL_CATCHED) {
ball.setTranslateY(Config.BAT_Y - ball.getDiameter());
}
}
} else if (bonus.getType() == Bonus.TYPE_LIFE) {
mainFrame.increaseLives();
updateLives();
}
}
}
}
if (state != PLAYING) {
return;
}
double newX = ball.getTranslateX() + ballDirX;
double newY = ball.getTranslateY() + ballDirY;
boolean inverseX = false;
boolean inverseY = false;
if (newX < 0) {
newX = -newX;
inverseX = true;
}
int BALL_MAX_X = Config.FIELD_WIDTH - ball.getDiameter();
if (newX > BALL_MAX_X) {
newX = BALL_MAX_X - (newX - BALL_MAX_X);
inverseX = true;
}
if (newY < Config.FIELD_Y) {
newY = 2 * Config.FIELD_Y - newY;
inverseY = true;
}
// Determine hit bat and ball
if (ballDirY > 0 &&
ball.getTranslateY() + ball.getDiameter() < Config.BAT_Y &&
newY + ball.getDiameter() >= Config.BAT_Y &&
newX >= bat.getTranslateX() - ball.getDiameter() &&
newX < bat.getTranslateX() + bat.getWidth() + ball.getDiameter()) {
inverseY = true;
// Speed up ball
double speed = Math.sqrt(ballDirX * ballDirX + ballDirY * ballDirY);
ballDirX *= (speed + Config.BALL_SPEED_INC) / speed;
ballDirY *= (speed + Config.BALL_SPEED_INC) / speed;
// Correct ballDirX and ballDirY
double offsetX = newX + ball.getDiameter() / 2 - bat.getTranslateX() - bat.getWidth() / 2;
// Don't change direction if center of bat was used
if (Math.abs(offsetX) > bat.getWidth() / 4) {
ballDirX += offsetX / 5;
double MAX_COORD_SPEED = Math.sqrt(speed * speed -
Config.BALL_MIN_COORD_SPEED * Config.BALL_MIN_COORD_SPEED);
if (Math.abs(ballDirX) > MAX_COORD_SPEED) {
ballDirX = Utils.sign(ballDirX) * MAX_COORD_SPEED;
}
ballDirY = Utils.sign(ballDirY) *
Math.sqrt(speed * speed - ballDirX * ballDirX);
}
correctBallSpeed();
if (catchedBonus == Bonus.TYPE_CATCH) {
newY = Config.BAT_Y - ball.getDiameter();
state = BALL_CATCHED;
}
}
// Determine hit ball and brick
int firstCol = (int)(newX / Config.BRICK_WIDTH);
int secondCol = (int)((newX + ball.getDiameter()) / Config.BRICK_WIDTH);
int firstRow = (int)((newY - Config.FIELD_Y) / Config.BRICK_HEIGHT);
int secondRow = (int)((newY - Config.FIELD_Y + ball.getDiameter()) / Config.BRICK_HEIGHT);
if (ballDirX > 0) {
int temp = secondCol;
secondCol = firstCol;
firstCol = temp;
}
if (ballDirY > 0) {
int temp = secondRow;
secondRow = firstRow;
firstRow = temp;
}
Brick vertBrick = getBrick(firstRow, secondCol);
Brick horBrick = getBrick(secondRow, firstCol);
if (vertBrick != null) {
kickBrick(firstRow, secondCol);
if (catchedBonus != Bonus.TYPE_STRIKE) {
inverseY = true;
}
}
if (horBrick != null &&
(firstCol != secondCol || firstRow != secondRow)) {
kickBrick(secondRow, firstCol);
if (catchedBonus != Bonus.TYPE_STRIKE) {
inverseX = true;
}
}
if (firstCol != secondCol || firstRow != secondRow) {
Brick diagBrick = getBrick(firstRow, firstCol);
if (diagBrick != null && diagBrick != vertBrick &&
diagBrick != horBrick) {
kickBrick(firstRow, firstCol);
if (vertBrick == null && horBrick == null &&
catchedBonus != Bonus.TYPE_STRIKE) {
inverseX = true;
inverseY = true;
}
}
}
ball.setTranslateX(newX);
ball.setTranslateY(newY);
if (inverseX) {
ballDirX = - ballDirX;
}
if (inverseY) {
ballDirY = - ballDirY;
}
if (ball.getTranslateY() > Config.SCREEN_HEIGHT) {
// Ball was lost
lostLife();
}
}
});
timeline.getKeyFrames().add(kf);
}
public void start() {
startingTimeline.play();
timeline.play();
group.getChildren().get(0).requestFocus();
updateScore(0);
updateLives();
}
public void stop() {
startingTimeline.stop();
timeline.stop();
}
private void initLevel() {
String[] level = LevelData.getLevelData(levelNumber);
for (int row = 0; row < level.length; row++) {
for (int col = 0; col < Config.FIELD_BRICK_IN_ROW; col++) {
String rowString = level[row];
Brick brick = null;
if (rowString != null && col < rowString.length()) {
String type = rowString.substring(col, col + 1);
if (!type.equals(" ")) {
brick = new Brick(Brick.getBrickType(type));
brick.setTranslateX(col * Config.BRICK_WIDTH);
brick.setTranslateY(Config.FIELD_Y + row * Config.BRICK_HEIGHT);
if (brick.getType() != Brick.TYPE_GREY) {
brickCount++;
}
}
}
bricks.add(brick);
}
}
}
private Brick getBrick(int row, int col) {
int i = row * Config.FIELD_BRICK_IN_ROW + col;
if (col < 0 || col >= Config.FIELD_BRICK_IN_ROW || row < 0 || i >= bricks.size()) {
return null;
} else {
return bricks.get(i);
}
}
private void updateScore(int inc) {
mainFrame.setScore(mainFrame.getScore() + inc);
score.setText(mainFrame.getScore() + "");
}
private void moveBat(double newX) {
double x = newX;
if (x < 0) {
x = 0;
}
if (x + bat.getWidth() > Config.FIELD_WIDTH) {
x = Config.FIELD_WIDTH - bat.getWidth();
}
if (state == BALL_CATCHED) {
double ballX = ball.getTranslateX() + x - bat.getTranslateX();
if (ballX < 0) {
ballX = 0;
}
double BALL_MAX_X = Config.FIELD_WIDTH - ball.getDiameter();
if (ballX > BALL_MAX_X) {
ballX = BALL_MAX_X;
}
ball.setTranslateX(ballX);
}
bat.setTranslateX(x);
}
private void kickBrick(int row, int col) {
Brick brick = getBrick(row, col);
if (brick == null || (catchedBonus != Bonus.TYPE_STRIKE && !brick.kick())) {
return;
}
updateScore(10);
if (brick.getType() != Brick.TYPE_GREY) {
brickCount--;
if (brickCount == 0) {
mainFrame.changeState(mainFrame.getState() + 1);
}
}
bricks.set(row * Config.FIELD_BRICK_IN_ROW + col, null);
fadeBricks.add(brick);
if (Utils.random(8) == 0 && bonuses.size() < 5) {
Bonus bonus = new Bonus(Utils.random(Bonus.COUNT));
bonus.setTranslateY(brick.getTranslateY());
bonus.setVisible(true);
bonus.setTranslateX(brick.getTranslateX() + (Config.BRICK_WIDTH - bonus.getWidth()) / 2);
group.getChildren().add(bonus);
bonuses.add(bonus);
}
}
private void updateLives() {
while (lives.size() > mainFrame.getLifeCount()) {
Bonus lifeBat = lives.get(lives.size() - 1);
lives.remove(lifeBat);
infoPanel.getChildren().remove(lifeBat);
}
// Add lifes (but no more than 9)
int maxVisibleLifes = 9;
double scale = 0.8;
for (int life = lives.size(); life < Math.min(mainFrame.getLifeCount(), maxVisibleLifes); life++) {
Bonus lifeBonus = new Bonus(Bonus.TYPE_LIFE);
lifeBonus.setScaleX(scale);
lifeBonus.setScaleY(scale);
lifeBonus.setTranslateX(livesCaption.getTranslateX() +
livesCaption.getBoundsInLocal().getWidth() + (life % 3) * lifeBonus.getWidth());
lifeBonus.setTranslateY(livesCaption.getTranslateY() +
(life / 3) * lifeBonus.getHeight() * MOB_SCALING);
lives.add(lifeBonus);
infoPanel.getChildren().add(lifeBonus);
}
}
private void correctBallSpeed() {
double speed = Math.sqrt(ballDirX * ballDirX + ballDirY * ballDirY);
if (speed > Config.BALL_MAX_SPEED) {
ballDirX *= Config.BALL_MAX_SPEED / speed;
ballDirY *= Config.BALL_MAX_SPEED / speed;
speed = Config.BALL_MAX_SPEED;
}
if (speed < Config.BALL_MIN_SPEED) {
ballDirX *= Config.BALL_MIN_SPEED / speed;
ballDirY *= Config.BALL_MIN_SPEED / speed;
speed = Config.BALL_MIN_SPEED;
}
if (Math.abs(ballDirX) < Config.BALL_MIN_COORD_SPEED) {
ballDirX = Utils.sign(ballDirX) * Config.BALL_MIN_COORD_SPEED;
ballDirY = Utils.sign(ballDirY) * Math.sqrt(speed * speed - ballDirX * ballDirX);
} else if (Math.abs(ballDirY) < Config.BALL_MIN_COORD_SPEED) {
ballDirY = Utils.sign(ballDirY) * Config.BALL_MIN_COORD_SPEED;
ballDirX = Utils.sign(ballDirX) * Math.sqrt(speed * speed - ballDirY * ballDirY);
}
}
private void lostLife() {
mainFrame.decreaseLives();
if (mainFrame.getLifeCount() < 0) {
state = GAME_OVER;
ball.setVisible(false);
bat.setVisible(false);
message.setImage(Config.getImages().get(Config.IMAGE_GAMEOVER));
message.setTranslateX((Config.FIELD_WIDTH - message.getImage().getWidth()) / 2);
message.setTranslateY(Config.FIELD_Y +
(Config.FIELD_HEIGHT - message.getImage().getHeight()) / 2);
message.setVisible(true);
message.setOpacity(1);
} else {
updateLives();
bat.changeSize(Bat.DEFAULT_SIZE);
ball.changeSize(Ball.DEFAULT_SIZE);
bat.setTranslateX((Config.FIELD_WIDTH - bat.getWidth()) / 2);
ball.setTranslateX(Config.FIELD_WIDTH / 2 - ball.getDiameter() / 2);
ball.setTranslateY(Config.BAT_Y - ball.getDiameter());
state = BALL_CATCHED;
catchedBonus = 0;
ballDirX = (Utils.random(2) * 2 - 1) * Config.BALL_MIN_COORD_SPEED;
ballDirY = - Config.BALL_MIN_SPEED;
}
}
private void initInfoPanel() {
infoPanel = new Group();
roundCaption = new Text();
roundCaption.setText("ROUND");
roundCaption.setTextOrigin(VPos.TOP);
roundCaption.setFill(Color.rgb(51, 102, 51));
Font f = new Font("Impact", 18);
roundCaption.setFont(f);
roundCaption.setTranslateX(30);
roundCaption.setTranslateY(128);
round = new Text();
round.setTranslateX(roundCaption.getTranslateX() +
roundCaption.getBoundsInLocal().getWidth() + Config.INFO_TEXT_SPACE);
round.setTranslateY(roundCaption.getTranslateY());
round.setText(levelNumber + "");
round.setTextOrigin(VPos.TOP);
round.setFont(f);
round.setFill(Color.rgb(0, 204, 102));
scoreCaption = new Text();
scoreCaption.setText("SCORE");
scoreCaption.setFill(Color.rgb(51, 102, 51));
scoreCaption.setTranslateX(30);
scoreCaption.setTranslateY(164);
scoreCaption.setTextOrigin(VPos.TOP);
scoreCaption.setFont(f);
score = new Text();
score.setTranslateX(scoreCaption.getTranslateX() +
scoreCaption.getBoundsInLocal().getWidth() + Config.INFO_TEXT_SPACE);
score.setTranslateY(scoreCaption.getTranslateY());
score.setFill(Color.rgb(0, 204, 102));
score.setTextOrigin(VPos.TOP);
score.setFont(f);
score.setText("");
livesCaption = new Text();
livesCaption.setText("LIFE");
livesCaption.setTranslateX(30);
livesCaption.setTranslateY(200);
livesCaption.setFill(Color.rgb(51, 102, 51));
livesCaption.setTextOrigin(VPos.TOP);
livesCaption.setFont(f);
Color INFO_LEGEND_COLOR = Color.rgb(0, 114, 188);
int infoWidth = Config.SCREEN_WIDTH - Config.FIELD_WIDTH;
Rectangle black = new Rectangle();
black.setWidth(infoWidth);
black.setHeight(Config.SCREEN_HEIGHT);
black.setFill(Color.BLACK);
ImageView verLine = new ImageView();
verLine.setImage(new Image(Level.class.getResourceAsStream(Config.IMAGE_DIR+"vline.png")));
verLine.setTranslateX(3);
ImageView logo = new ImageView();
logo.setImage(Config.getImages().get(Config.IMAGE_LOGO));
logo.setTranslateX(30);
logo.setTranslateY(30);
Text legend = new Text();
legend.setTranslateX(30);
legend.setTranslateY(310);
legend.setText("LEGEND");
legend.setFill(INFO_LEGEND_COLOR);
legend.setTextOrigin(VPos.TOP);
legend.setFont(new Font("Impact", 18));
infoPanel.getChildren().addAll(black, verLine, logo, roundCaption,
round, scoreCaption, score, livesCaption, legend);
for (int i = 0; i < Bonus.COUNT; i++) {
Bonus bonus = new Bonus(i);
Text text = new Text();
text.setTranslateX(100);
text.setTranslateY(350 + i * 40);
text.setText(Bonus.NAMES[i]);
text.setFill(INFO_LEGEND_COLOR);
text.setTextOrigin(VPos.TOP);
text.setFont(new Font("Arial", 12));
bonus.setTranslateX(30 + (820 - 750 - bonus.getWidth()) / 2);
bonus.setTranslateY(text.getTranslateY() -
(bonus.getHeight() - text.getBoundsInLocal().getHeight()) / 2);
// Workaround JFXC-2379
infoPanel.getChildren().addAll(bonus, text);
}
infoPanel.setTranslateX(Config.FIELD_WIDTH);
}
private void initContent(int level) {
catchedBonus = 0;
state = STARTING_LEVEL;
batDirection = 0;
levelNumber = level;
lives = new ArrayList<Bonus>();
bricks = new ArrayList<Brick>();
fadeBricks = new ArrayList<Brick>();
bonuses = new ArrayList<Bonus>();
ball = new Ball();
ball.setVisible(false);
bat = new Bat();
bat.setTranslateY(Config.BAT_Y);
bat.setVisible(false);
message = new ImageView();
message.setImage(Config.getImages().get(Config.IMAGE_READY));
message.setTranslateX((Config.FIELD_WIDTH - message.getImage().getWidth()) / 2);
message.setTranslateY(Config.FIELD_Y +
(Config.FIELD_HEIGHT - message.getImage().getHeight()) / 2);
message.setVisible(false);
initLevel();
initStartingTimeline();
initTimeline();
initInfoPanel();
ImageView background = new ImageView();
background.setFocusTraversable(true);
background.setImage(Config.getImages().get(Config.IMAGE_BACKGROUND));
background.setFitWidth(Config.SCREEN_WIDTH);
background.setFitHeight(Config.SCREEN_HEIGHT);
background.setOnMouseMoved(new EventHandler<MouseEvent>() {
public void handle(MouseEvent me) {
moveBat(me.getX() - bat.getWidth() / 2);
}
});
background.setOnMouseDragged(new EventHandler<MouseEvent>() {
public void handle(MouseEvent me) {
// Support touch-only devices like some mobile phones
moveBat(me.getX() - bat.getWidth() / 2);
}
});
background.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent me) {
if (state == PLAYING) {
// Support touch-only devices like some mobile phones
moveBat(me.getX() - bat.getWidth() / 2);
}
if (state == BALL_CATCHED) {
state = PLAYING;
}
if (state == GAME_OVER) {
mainFrame.changeState(MainFrame.SPLASH);
}
}
});
background.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(KeyEvent ke) {
if ((ke.getCode() == KeyCode.POWER) || (ke.getCode() == KeyCode.X)) {
Platform.exit();
}
if (state == BALL_CATCHED && (ke.getCode() == KeyCode.SPACE ||
ke.getCode() == KeyCode.ENTER || ke.getCode() == KeyCode.PLAY)) {
state = PLAYING;
}
if (state == GAME_OVER) {
mainFrame.changeState(MainFrame.SPLASH);
}
if (state == PLAYING && ke.getCode() == KeyCode.Q) {
// Lost life
lostLife();
return;
}
if ((ke.getCode() == KeyCode.LEFT || ke.getCode() == KeyCode.TRACK_PREV)) {
batDirection = - Config.BAT_SPEED;
}
if ((ke.getCode() == KeyCode.RIGHT || ke.getCode() == KeyCode.TRACK_NEXT)) {
batDirection = Config.BAT_SPEED;
}
}
});
background.setOnKeyReleased(new EventHandler<KeyEvent>() {
public void handle(KeyEvent ke) {
if (ke.getCode() == KeyCode.LEFT || ke.getCode() == KeyCode.RIGHT ||
ke.getCode() == KeyCode.TRACK_PREV || ke.getCode() == KeyCode.TRACK_NEXT) {
batDirection = 0;
}
}
});
group.getChildren().add(background);
for (int row = 0; row < bricks.size()/Config.FIELD_BRICK_IN_ROW; row++) {
for (int col = 0; col < Config.FIELD_BRICK_IN_ROW; col++) {
Brick b = getBrick(row, col);
if (b != null) { //tmp
group.getChildren().add(b);
}
}
}
group.getChildren().addAll(message, ball, bat, infoPanel);
}
}