In my javafx project, i have a gridpane of cells with a main character and four enemies. The main character moves when the arrow keys are hit. The problem is that when the board is 4*4 and I hit an arrow key, it takes two seconds for the main character to move, and when the size of board is 10*10, after the first two arrow key hits nothing happens, and the third time gives me JavaFX Application Thread Out Of Memory Error: Java Heap Space.
I have no idea what is causing this problem. What object is getting newed so many times it fills all the RAM? Any solutions for how to fix this code?
package project.view;
import javafx.animation.FadeTransition;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
import java.net.URL;
import project.controller.GameController;
import project.model.*;
import project.transition.FlipTransition;
import project.view.components.CardView;
import javafx.scene.Parent;
import javafx.scene.Scene;
import static javafx.scene.input.KeyCode.DOWN;
public class GameView extends Application implements EventHandler<MouseEvent> {
public GridPane gameBoard;
public BorderPane borderPane;
private static CardView[][] cards = new CardView[GameBoard.getGameBoards().get(0).getMazeCreator().getBoard().length][GameBoard.getGameBoards().get(0).getMazeCreator().getBoard()[0].length()];
public GameBoard gameBoardInCode;
public static Stage stage;
public static Scene scene;
public static Timeline timeline;
#Override
public void start(Stage stage) throws Exception {Scene(FXMLLoader.load(getClass().getResource("/project/fxml/game_board.fxml")))
GameView.stage = stage;
URL url = getClass().getResource("/project/fxml/game_board.fxml");
Parent root = FXMLLoader.load(url);
System.out.println(url.toString());
Scene scene = new Scene(root);
stage.setScene(scene);
GameView.scene = scene;
scene.setOnKeyPressed(key -> {
if (key.getCode() == KeyCode.UP || key.getCode() == KeyCode.DOWN || key.getCode() == KeyCode.LEFT || key.getCode() == KeyCode.RIGHT) {
moveMainCharacterInView(key);
return;
}
});
stage.setTitle("New Game");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
#FXML
public void initialize() {
int rows = GameBoard.getGameBoards().get(0).getMazeCreator().getBoard().length;
int columns = GameBoard.getGameBoards().get(0).getMazeCreator().getBoard()[0].length();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
CardView rectangle = getUpdatedCardRectangle(i, j);
gameBoard.add(rectangle, j, i);
cards[i][j] = rectangle;
}
}
GridPane.setHalignment(gameBoard, HPos.CENTER);
gameBoard.setAlignment(Pos.CENTER);
}
public static void updateBoard() {
int rows = GameBoard.getGameBoards().get(0).getMazeCreator().getBoard().length;
int columns = GameBoard.getGameBoards().get(0).getMazeCreator().getBoard()[0].length();
GridPane gameBoard = (GridPane) stage.getScene().lookup("#1");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
CardView rectangle = getUpdatedCardRectangle(i, j);
gameBoard.add(rectangle, j, i);
cards[i][j] = rectangle;
}
}
gameBoard.setAlignment(Pos.CENTER);
}
public static void moveMainCharacterInView(KeyEvent event) {
if (event.getCode() == KeyCode.UP) {
System.out.println("UP");
if (GameBoard.getGameBoards().size() != 0) {
GameBoard.getGameBoards().get(0).getMainCharacter().moveMainCharacter("up");
updateBoard();
}
} else if (event.getCode() == KeyCode.RIGHT) {
System.out.println("RIGHT");
if (GameBoard.getGameBoards().size() != 0) {
GameBoard.getGameBoards().get(0).getMainCharacter().moveMainCharacter("right");
updateBoard();
}
} else if (event.getCode() == KeyCode.LEFT) {
System.out.println("LEFT");
if (GameBoard.getGameBoards().size() != 0) {
GameBoard.getGameBoards().get(0).getMainCharacter().moveMainCharacter("left");
updateBoard();
}
} else if (event.getCode() == DOWN) {
System.out.println("DOWN");
if (GameBoard.getGameBoards().size() != 0) {
GameBoard.getGameBoards().get(0).getMainCharacter().moveMainCharacter("down");
updateBoard();
}
}
}
private static CardView getUpdatedCardRectangle(int i, int j) {
CardView rectangle = new CardView();
Card card = Card.getAllCards()[i][j];
if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("2")) {
card = new Card(CellSituation.Enemy_1, i, j);
} else if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("3")) {
card = new Card(CellSituation.Enemy_2, i, j);
} else if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("4")) {
card = new Card(CellSituation.Enemy_3, i, j);
} else if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("5")) {
card = new Card(CellSituation.Enemy_4, i, j);
} else if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("6")) {
card = new Card(CellSituation.MAINCHARACTER, i, j);
} else if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("*")) {
card = new Card(CellSituation.EMPTY, i, j);
} else if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("1")) {
card = new Card(CellSituation.UNPASSABLE, i, j);
} else if (GameBoard.getGameBoards().get(0).getMazeCreator().giveContentOfBoard(i, j, j + 1).equals("0")) {
card = new Card(CellSituation.PASSABLE, i, j);
}
rectangle.setFill(card.getFrontImage());
if (card.getCellSituation().equals(CellSituation.PASSABLE) || card.getCellSituation().equals(CellSituation.UNPASSABLE)) {
if (i % 2 == 0 && j % 2 == 1) {
rectangle.setHeight(3);
rectangle.setWidth(50);
}
if (i % 2 == 1 && j % 2 == 0) {
rectangle.setHeight(50);
rectangle.setWidth(3);
}
if (i % 2 == 0 && j % 2 == 0) {
rectangle.setHeight(3);
rectangle.setWidth(3);
}
} else {
rectangle.setHeight(50);
rectangle.setWidth(50);
}
rectangle.setI(card.getI());
rectangle.setJ(card.getJ());
return rectangle;
}
}
Related
I am trying to build a Rubiks Cube from scratch as my first real app using JavaFx. In the Moves class Im selecting Boxes from ObservableList based on position. The problem is that the Box.getTranslate dosent update so when I try to move the front and the left faces successively the Boxes selected by both are always moved resulting in.. chaos. How could I re-write this so that the Move methods correctly select the boxes to move? Here is the code, work in progress.
Main
package ro.adrianpush;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Box;
import javafx.stage.Stage;
public class Main extends Application {
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
final Group root = new Group();
#Override
public void start(Stage primaryStage) throws Exception{
Camera camera = new PerspectiveCamera();
camera.translateXProperty().setValue(-200);
camera.translateYProperty().setValue(0);
camera.translateZProperty().set(-500);
AnchorPane pane = new AnchorPane();
Rubik rubik = new Rubik();
ObservableList<Box> boxArrayList = rubik.getBoxArrayList();
for (Box box: boxArrayList
) {
pane.getChildren().addAll(box);
}
primaryStage.addEventHandler(KeyEvent.KEY_PRESSED, event -> {
switch (event.getCode()){
case E:
Moves.rotateFront(boxArrayList, "clockwise");
break;
case Q:
Moves.rotateFront(boxArrayList, "counterclockwise");
break;
case A:
Moves.rotateLeft(boxArrayList, "clockwise");
break;
case D:
Moves.rotateLeft(boxArrayList, "counterclockwise");
break;
}
});
root.getChildren().add(pane);
Scene scene = new Scene(root, WIDTH, HEIGHT, true);
scene.setCamera(camera);
scene.setFill(Color.ROYALBLUE);
primaryStage.setTitle("The game nobody wants to play");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Rubik
package ro.adrianpush;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.shape.Box;
public class Rubik {
private ObservableList<Box> boxArrayList = FXCollections.observableArrayList();
public Rubik(){
for(int i = 1; i < 4; i+=1){
for( int j = 1; j < 4; j++){
for(int k = 1; k < 4; k++){
Box box = new Box(100,100,100);
box.setTranslateX(i*100);
box.setTranslateY(j*100);
box.setTranslateZ(k*100);
boxArrayList.add(box);
}
}
}
}
public ObservableList<Box> getBoxArrayList() {
return boxArrayList;
}
}
Moves
package ro.adrianpush;
import javafx.collections.ObservableList;
import javafx.scene.shape.Box;
import javafx.scene.transform.Rotate;
public class Moves {
public static void rotateFront(ObservableList<Box> boxArrayList, String direction) {
for (Box box: boxArrayList
) {
if(box.getTranslateZ() == 100){
Rotate rotate = new Rotate();
rotate.setAxis(Rotate.Z_AXIS);
if(direction == "clockwise"){
rotate.setAngle(5);
} else if (direction == "counterclockwise"){
rotate.setAngle(-5);
}
if(box.getTranslateX() == 100){
rotate.setPivotX(100);
} if (box.getTranslateX() == 300){
rotate.setPivotX(-100);
} if(box.getTranslateY() == 100){
rotate.setPivotY(100);
} if(box.getTranslateY() == 300){
rotate.setPivotY(-100);
}
box.getTransforms().add(rotate);
}
}
}
public static void rotateBack(ObservableList<Box> boxArrayList, String direction) {
for (Box box: boxArrayList
) {
if(box.getTranslateZ() == 300){
Rotate rotate = new Rotate();
if(direction == "clockwise"){
rotate.setAngle(5);
} else if (direction == "counterclockwise"){
rotate.setAngle(-5);
}
if(box.getTranslateX() == 100){
rotate.setPivotX(100);
} if (box.getTranslateX() == 300){
rotate.setPivotX(-100);
} if(box.getTranslateY() == 100){
rotate.setPivotY(100);
} if(box.getTranslateY() == 300){
rotate.setPivotY(-100);
}
box.getTransforms().add(rotate);
}
}
}
public static void rotateLeft(ObservableList<Box> boxArrayList, String direction) {
for (Box box: boxArrayList
) {
if(box.getTranslateX() == 100){
Rotate rotate = new Rotate();
rotate.setAxis(Rotate.X_AXIS);
if(direction == "clockwise"){
rotate.setAngle(5);
} else if (direction == "counterclockwise"){
rotate.setAngle(-5);
}
if(box.getTranslateY() == 100){
rotate.setPivotY(100);
} if (box.getTranslateY() == 300){
rotate.setPivotY(-100);
} if(box.getTranslateZ() == 100){
rotate.setPivotZ(100);
} if(box.getTranslateZ() == 300){
rotate.setPivotZ(-100);
}
box.getTransforms().add(rotate);
}
}
}
}
Can someone explain how to solve this? DeleteRows() method is not working as intended.
It's a Tetris game and I'm trying to delete rows. When the blocks move down, the blocks are still counted as 0 so new blocks go through them. But this occurs only in the top row of the moved blocks:
package application;
import java.util.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Tetris extends Application {
public static final int MOVE_AMOUNT = 25;
public static final int SIZE = 25;
public static int XLIMIT = SIZE * 10;
public static int YLIMIT = SIZE * 24;
public static int[][] GRID = new int[XLIMIT/SIZE][YLIMIT/SIZE];
private static Pane group = new Pane();
private static Shape object;
private static Scene scene = new Scene(group, XLIMIT, YLIMIT);
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) throws Exception {
for(int[] a: GRID){
Arrays.fill(a, 0);
}
for(int i = 0; i <= XLIMIT; i+= SIZE){
Line a = new Line(i, 0, i, YLIMIT);
group.getChildren().add(a);
}
for(int i = 0; i <= YLIMIT; i+= SIZE){
Line a = new Line(0, i, XLIMIT, i);
group.getChildren().add(a);
}
for(int i = 0; i <= YLIMIT; i+= SIZE){
Text a = new Text("" + i);
a.setY(i);
group.getChildren().add(a);
}
for(int i = SIZE; i < XLIMIT; i+= SIZE){
Text a = new Text("" + i);
a.setY(10);
a.setX(i);
group.getChildren().add(a);
}
Shape a = TetrisHolder.createRect();
group.getChildren().addAll(a.a, a.b, a.c, a.d);
moveOnKeyPress(scene, a.a, a.b, a.c, a.d);
object = a;
stage.setScene(scene);
stage.show();
Timer myTimer=new Timer();
TimerTask task =new TimerTask() {
#Override
public void run() {
Platform.runLater(new Runnable(){
public void run(){
CheckDown(object);
}
});
}
};
myTimer.schedule(task,0,300);
}
private void moveOnKeyPress(Scene scene, Rectangle rect, Rectangle rect2, Rectangle rect3, Rectangle rect4) {
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override public void handle(KeyEvent event) {
Shape shape = new Shape(rect, rect2, rect3, rect4);
switch (event.getCode()) {
case RIGHT:
TetrisHolder.CheckRight(shape);
break;
case DOWN:
CheckDown(shape);
break;
case LEFT:
TetrisHolder.CheckLeft(shape);
break;
case UP:
//TetrisHolder.CheckTurn(shape);
break;
}
}
});
}
private void CheckTurn(Shape shape){
}
private void DeleteRows(Pane pane){
ArrayList<Node> rects = new ArrayList<Node>();
ArrayList<Integer> lines = new ArrayList<Integer>();
int full = 0;
for(int i = 0; i < GRID[0].length; i++){
for(int j = 0; j < GRID.length; j++){
if(GRID[j][i] == 1)
full++;
}
if(full == GRID.length)
lines.add(i/*+lines.size()*/);
full = 0;
}
for(Node node: pane.getChildren()) {
if(node instanceof Rectangle) {
rects.add(node);
}
}
if(lines.size() > 0)
do{
for(Node node: rects){
Rectangle a = (Rectangle)node;
if(a.getY() == lines.get(0)*SIZE){
GRID[(int)a.getX()/SIZE][(int)a.getY()/SIZE] = 0;
pane.getChildren().remove(node);
}
if(a.getY() < lines.get(0)*SIZE){
GRID[(int)a.getX()/SIZE][(int)a.getY()/SIZE] = 0;
a.setY(a.getY() + SIZE);
GRID[(int)a.getX()/SIZE][(int)a.getY()/SIZE] = 1;
}
}
lines.remove(0);
rects.clear();
for(Node node: pane.getChildren()) {
if(node instanceof Rectangle) {
rects.add(node);
}
}
} while(lines.size() > 0);
}
private void CheckDown(Shape shape){
if((shape.c.getY() == YLIMIT - SIZE) || checkA(shape) || checkB(shape) || checkC(shape) || checkD(shape)){
GRID[(int)shape.a.getX()/SIZE][(int)shape.a.getY()/SIZE] = 1;
GRID[(int)shape.b.getX()/SIZE][(int)shape.b.getY()/SIZE] = 1;
GRID[(int)shape.c.getX()/SIZE][(int)shape.c.getY()/SIZE] = 1;
GRID[(int)shape.d.getX()/SIZE][(int)shape.d.getY()/SIZE] = 1;
DeleteRows(group);
Shape a = TetrisHolder.createRect();
object = a;
group.getChildren().addAll(a.a, a.b, a.c, a.d);
moveOnKeyPress(shape.a.getScene(), a.a, a.b, a.c, a.d);
}
if(shape.c.getY() + MOVE_AMOUNT < YLIMIT){
int checka = GRID[(int)shape.a.getX()/SIZE][((int)shape.a.getY()/SIZE) + 1];
int checkb = GRID[(int)shape.b.getX()/SIZE][((int)shape.b.getY()/SIZE) + 1];
int checkc = GRID[(int)shape.c.getX()/SIZE][((int)shape.c.getY()/SIZE) + 1];
int checkd = GRID[(int)shape.d.getX()/SIZE][((int)shape.d.getY()/SIZE) + 1];
if(checka == 0 && checka == checkb && checkb == checkc && checkc == checkd){
shape.a.setY(shape.a.getY() + MOVE_AMOUNT);
shape.b.setY(shape.b.getY() + MOVE_AMOUNT);
shape.c.setY(shape.c.getY() + MOVE_AMOUNT);
shape.d.setY(shape.d.getY() + MOVE_AMOUNT);
}
}
}
private boolean checkA(Shape shape){
return (GRID[(int)shape.a.getX()/SIZE][((int)shape.a.getY()/SIZE) + 1] == 1);
}
private boolean checkB(Shape shape){
return (GRID[(int)shape.b.getX()/SIZE][((int)shape.b.getY()/SIZE) + 1] == 1);
}
private boolean checkC(Shape shape){
return (GRID[(int)shape.c.getX()/SIZE][((int)shape.c.getY()/SIZE) + 1] == 1);
}
private boolean checkD(Shape shape){
return (GRID[(int)shape.d.getX()/SIZE][((int)shape.d.getY()/SIZE) + 1] == 1);
}
}
This is the code. The problem is at DeleteRows() method.
I am trying to make a puzzle game but the problem is that I can't do the EventHandler setOnMouseClicked.Also I want to know how to make possible that to re-arrange the puzzle so it shows random images in every-coordinate. This is how far I got.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class eliss extends Application{
#Override
public void start(Stage primaryStage) {
ImageView view[][] = new ImageView[5][5];
Image imag = new Image("http://images.cdn.autocar.co.uk/sites/autocar.co.uk/files/styles/gallery_slide/public/ferrari-laferrari-zfye-059_1.jpg?itok=hfLNxUD9",600,600,false,true);
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setVgap(2);
pane.setHgap(2);
PuzzleImage(view, imag, pane);
Scene scene = new Scene(pane,1100,1100);
primaryStage.setTitle("Elis");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] x)
{
launch(x);
}
public void PuzzleImage( ImageView view[][],Image imag,GridPane pane)
{
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
if(j==4 && i==4) view[i][j]=null;
else{
view[i][j]=new ImageView(imag);
Rectangle2D rect = new Rectangle2D(120*i,120*j,120,120);
view[i][j].setViewport(rect);
pane.add(view[i][j], i, j);
}
}
}
}
}
What you are asking is too much for a question on StackOverflow. However, I got a little bit of spare time, so I quickly drafted up some code to demonstrate what you need:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PuzzleGame extends Application {
private Image image = new Image("http://images.cdn.autocar.co.uk/sites/autocar.co.uk/files/styles/gallery_slide/public/ferrari-laferrari-zfye-059_1.jpg?itok=hfLNxUD9",600,600,false,true);
private static double SCENE_WIDTH = 1024;
private static double SCENE_HEIGHT = 768;
public static int TILE_ROW_COUNT = 5;
public static int TILE_COLUMN_COUNT = 5;
public static double TILE_SIZE = 120;
public static double offsetX = (SCENE_WIDTH - TILE_ROW_COUNT * TILE_SIZE) / 2;
public static double offsetY = (SCENE_HEIGHT - TILE_COLUMN_COUNT * TILE_SIZE) / 2;
List<Cell> cells = new ArrayList<>();
#Override
public void start(Stage primaryStage) {
// create grid
for (int x = 0; x < TILE_ROW_COUNT; x++) {
for (int y = 0; y < TILE_COLUMN_COUNT; y++) {
// create tile
ImageView tile = new ImageView(image);
Rectangle2D rect = new Rectangle2D(TILE_SIZE * x, TILE_SIZE * y, TILE_SIZE, TILE_SIZE);
tile.setViewport(rect);
// consider empty cell, let it remain empty
if (x == (TILE_ROW_COUNT - 1) && y == (TILE_COLUMN_COUNT - 1)) {
tile = null;
}
cells.add(new Cell(x, y, tile));
}
}
// shuffle cells
shuffle();
// create playfield
Pane pane = new Pane();
// put tiles on playfield, assign event handler
for (int i = 0; i < cells.size(); i++) {
Cell cell = cells.get(i);
Node imageView = cell.getImageView();
// consider empty cell
if (imageView == null)
continue;
// click-handler: swap tiles, check if puzzle is solved
imageView.addEventFilter(MouseEvent.MOUSE_CLICKED, mouseEvent -> {
moveCell((Node) mouseEvent.getSource());
});
// position images on scene
imageView.relocate(cell.getLayoutX(), cell.getLayoutY());
pane.getChildren().add(cell.getImageView());
}
Scene scene = new Scene(pane, SCENE_WIDTH, SCENE_HEIGHT);
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* Swap images of cells randomly
*/
public void shuffle() {
Random rnd = new Random();
for (int i = 0; i < 1000; i++) {
int a = rnd.nextInt(cells.size());
int b = rnd.nextInt(cells.size());
if (a == b)
continue;
// skip bottom right cell swap, we want the empty cell to remain there
if( cells.get(a).isEmpty() || cells.get(b).isEmpty())
continue;
swap( cells.get(a), cells.get(b));
}
}
public void swap( Cell cellA, Cell cellB) {
ImageView tmp = cellA.getImageView();
cellA.setImageView(cellB.getImageView());
cellB.setImageView(tmp);
}
public boolean checkSolved() {
boolean allSolved = true;
for (Cell cell : cells) {
if (!cell.isSolved()) {
allSolved = false;
break;
}
}
System.out.println("Solved: " + allSolved);
return allSolved;
}
public void moveCell(Node node) {
// get current cell using the selected node (imageview)
Cell currentCell = null;
for (Cell tmpCell : cells) {
if (tmpCell.getImageView() == node) {
currentCell = tmpCell;
break;
}
}
if (currentCell == null)
return;
// get empty cell
Cell emptyCell = null;
for (Cell tmpCell : cells) {
if (tmpCell.isEmpty()) {
emptyCell = tmpCell;
break;
}
}
if (emptyCell == null)
return;
// check if cells are swappable: neighbor distance either x or y must be 1 for a valid move
int steps = Math.abs(currentCell.x - emptyCell.x) + Math.abs(currentCell.y - emptyCell.y);
if (steps != 1)
return;
System.out.println("Transition: " + currentCell + " -> " + emptyCell);
// cells are swappable => create path transition
Path path = new Path();
path.getElements().add(new MoveToAbs(currentCell.getImageView(), currentCell.getLayoutX(), currentCell.getLayoutY()));
path.getElements().add(new LineToAbs(currentCell.getImageView(), emptyCell.getLayoutX(), emptyCell.getLayoutY()));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(100));
pathTransition.setNode(currentCell.getImageView());
pathTransition.setPath(path);
pathTransition.setOrientation(PathTransition.OrientationType.NONE);
pathTransition.setCycleCount(1);
pathTransition.setAutoReverse(false);
final Cell cellA = currentCell;
final Cell cellB = emptyCell;
pathTransition.setOnFinished(actionEvent -> {
swap( cellA, cellB);
checkSolved();
});
pathTransition.play();
}
private static class Cell {
int x;
int y;
ImageView initialImageView;
ImageView currentImageView;
public Cell(int x, int y, ImageView initialImageView) {
super();
this.x = x;
this.y = y;
this.initialImageView = initialImageView;
this.currentImageView = initialImageView;
}
public double getLayoutX() {
return x * TILE_SIZE + offsetX;
}
public double getLayoutY() {
return y * TILE_SIZE + offsetY;
}
public ImageView getImageView() {
return currentImageView;
}
public void setImageView(ImageView imageView) {
this.currentImageView = imageView;
}
public boolean isEmpty() {
return currentImageView == null;
}
public boolean isSolved() {
return this.initialImageView == currentImageView;
}
public String toString() {
return "[" + x + "," + y + "]";
}
}
// absolute (layoutX/Y) transitions using the pathtransition for MoveTo
public static class MoveToAbs extends MoveTo {
public MoveToAbs(Node node) {
super(node.getLayoutBounds().getWidth() / 2, node.getLayoutBounds().getHeight() / 2);
}
public MoveToAbs(Node node, double x, double y) {
super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
// absolute (layoutX/Y) transitions using the pathtransition for LineTo
public static class LineToAbs extends LineTo {
public LineToAbs(Node node, double x, double y) {
super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
public static void main(String[] args) {
launch(args);
}
}
You can use Collections.shuffle to generate a random permutation of a List This can be used to place the tiles in a random order:
private static final int COLUMN_COUNT = 5;
private static final int ROW_COUNT = 5;
private static void fillGridPane(GridPane pane, ImageView[][] view, Image imag) {
List<ImageView> images = new ArrayList<>(24);
for (int i = 0; i < COLUMN_COUNT; i++) {
for (int j = 0, end = i == (COLUMN_COUNT - 1) ? ROW_COUNT - 1 : ROW_COUNT; j < end; j++) {
ImageView iv = new ImageView(imag);
images.add(iv);
view[i][j] = iv;
Rectangle2D rect = new Rectangle2D(120 * i, 120 * j, 120, 120);
iv.setViewport(rect);
}
}
Collections.shuffle(images);
Iterator<ImageView> iter = images.iterator();
for (int i = 0; i < COLUMN_COUNT; i++) {
for (int j = 0, end = i == (COLUMN_COUNT - 1) ? ROW_COUNT - 1 : ROW_COUNT; j < end; j++) {
pane.add(iter.next(), i, j);
}
}
}
The onMouseClicked event handler can be attached to the GridPane and MouseEvent.getTarget can be used to get the node that was clicked:
pane.setOnMouseClicked(event -> {
if (move(event)) {
if (checkWin()) {
new Alert(Alert.AlertType.INFORMATION, "You Win!").show();
}
}
});
private int emptyTileX = 4;
private int emptyTileY = 4;
private boolean move(MouseEvent event) {
Object target = event.getTarget();
if (target instanceof ImageView) {
ImageView iv = (ImageView) target;
int row = GridPane.getRowIndex(iv);
int column = GridPane.getColumnIndex(iv);
int dx = Math.abs(column - emptyTileX);
int dy = Math.abs(row - emptyTileY);
if ((dx == 0 && dy == 1) || (dx == 1 && dy == 0)) {
// swap image and empty tile, if they are next to each other
GridPane.setConstraints(iv, emptyTileX, emptyTileY);
emptyTileX = column;
emptyTileY = row;
return true;
}
}
return false;
}
To check the winning condition, you can simply check the positions of the ImageViews in the GridPane
private boolean checkWin() {
for (int i = 0; i < COLUMN_COUNT; i++) {
for (int j = 0, end = i == (COLUMN_COUNT - 1) ? ROW_COUNT - 1 : ROW_COUNT; j < end; j++) {
ImageView iv = view[i][j];
if (GridPane.getColumnIndex(iv) != i || GridPane.getRowIndex(iv) != j) {
return false;
}
}
}
return true;
}
for this application, I need to enter a number and display the numbers that when multiplied together will give you the number in question. For example, if you enter 42 then the labels for 6*7 and 7*6 would change color. I figured out how to get the answers but I cant quite figure out how to manipulate the labels in the multiplication table to change color. To give you an idea,
main class
package application;
import java.util.List;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane pane = new BorderPane();
pane.setTop(getHbox1());
HBox prompt = new HBox(15);
prompt.setPadding(new Insets(15, 15, 15, 15));
prompt.setAlignment(Pos.TOP_CENTER);
prompt.getStyleClass().add("hbox2");
Label lblProblem = new Label("Enter problem: ");
prompt.getChildren().add(lblProblem);
TextField tfProblem = new TextField();
prompt.getChildren().add(tfProblem);
Button btnFindAnswer = new Button("Find answers");
btnFindAnswer.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>() {
#Override
public void handle(Event arg0) {
int x = showFactors(tfProblem);
}
});
prompt.getChildren().add(btnFindAnswer);
pane.setCenter(prompt);
pane.setBottom(setUpGrid());
Scene scene = new Scene(pane, 550, 650);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("lab 7");
primaryStage.setScene(scene);
primaryStage.show();
}
private HBox getHbox1() {
HBox hbox = new HBox(15);
hbox.setPadding(new Insets(15, 15, 15, 15));
hbox.setAlignment(Pos.TOP_CENTER);
hbox.getStyleClass().add("hbox1");
Label lblProblem = new Label("Reverse Multiplication Table");
hbox.getChildren().add(lblProblem);
return hbox;
}
public GridPane setUpGrid() {
GridPane pane = new GridPane();
Label[][] labels = new Label[11][11];
for (int row = 0; row < 11; row++)
for (int col = 0; col < 11; col++) {
Label l = new Label();
setUpLabel(l, col, row);
labels[row][col] = l;
pane.add(l, col, row);
}
return pane;
}
public void setUpLabel(final Label l, final int col, final int row) {
l.setPrefHeight(50);
l.setPrefWidth(50);
l.setAlignment(Pos.CENTER);
l.setStyle("-fx-stroke-border: black; -fx-border-width: 1;");
String a = String.valueOf(row);
String b = String.valueOf(col);
if (row == 0 || col == 0) {
l.getStyleClass().add("gridBorders");
if(row == 0)
l.setText(b);
else if (col == 0)
l.setText(a);
} else {
l.setText(a + " * " + b);
l.getStyleClass().add("gridInside");
}
}
public int showFactors(TextField problem) {
FactorCalculator calc = new FactorCalculator();
int number = Integer.parseInt(problem.getText());
List<Integer> factors = calc.findFactor(number);
for(int i = 0; i < factors.size() - 1; i++) {
return factors.get(i);
}
return 0;
}
public static void main(String[] args) {
launch(args);
}
}
factorCalculator class
package application;
import java.util.ArrayList;
import java.util.List;
public class FactorCalculator {
public List<Integer> list = new ArrayList<Integer>();
public List<Integer> findFactor(int problem) {
int incrementer = 1;
if(problem % 2 != 0) {
incrementer = 2;
}
while(incrementer <= problem) {
if(problem % incrementer == 0) {
list.add(incrementer);
}
incrementer++;
}
return list;
}
}
application css
{
-fx-text-alignment: center;
}
.hbox1 {
-fx-background-color: gray;
}
.hbox2 {
-fx-background-color: white;
}
.gridBorders {
-fx-background-color: gray;
-fx-text-fill:#A3FF47;
-fx-border-style: solid;
-fx-border-width: 1;
-fx-stroke-border: black;
}
.gridInside {
-fx-background-color: red;
-fx-text-fill: white;
-fx-border-style: solid;
-fx-border-width: 1;
-fx-stroke-border: black;
}
.gridAnswer {
-fx-background-color: white;
-fx-text-fill: black;
}
Just use your style "gridAnswer" and set it
l.getStyleClass().add( "gridAnswer");
or remove it
l.getStyleClass().remove( "gridAnswer");
depending on your needs.
Edit: May I suggest a different approach?
Just create a custom cell which has all the information you need. Something like this:
private class AnswerCell extends Label {
int a;
int b;
int value;
public AnswerCell( int a, int b) {
this.a = a;
this.b = b;
this.value = a * b;
setText( a + " * " + b);
}
public boolean matches( int matchValue) {
return value == matchValue;
}
public void highlight() {
getStyleClass().add( "gridAnswer");
}
public void unhighlight() {
getStyleClass().remove( "gridAnswer");
}
}
In your setup method you simply add the cells and put them into a global list:
List<AnswerCell> answerCells = new ArrayList<>();
And to find the answers you do this:
for( AnswerCell cell: answerCells) {
cell.unhighlight();
}
for( AnswerCell cell: answerCells) {
if( cell.matches(number)) {
cell.highlight();
}
}
ReverseMultiplication.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package reversemultiplication;
import java.util.List;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author reegan
*/
public class ReverseMultiplication extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane pane = new BorderPane();
pane.setTop(getHbox1());
HBox prompt = new HBox(15);
prompt.setPadding(new Insets(15, 15, 15, 15));
prompt.setAlignment(Pos.TOP_CENTER);
prompt.getStyleClass().add("hbox2");
Label lblProblem = new Label("Enter problem: ");
prompt.getChildren().add(lblProblem);
TextField tfProblem = new TextField();
prompt.getChildren().add(tfProblem);
GridPane gridPane = setUpGrid();
GridpaneHelper gh = new GridpaneHelper(gridPane);
Button btnFindAnswer = new Button("Find answers");
btnFindAnswer.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>() {
#Override
public void handle(Event arg0) {
List<int[]> x = showFactors(tfProblem);
for (int[] x1 : x) {
Node node = gh.getChildren()[x1[0]][x1[1]];
node.setStyle("-fx-background-color: green");
}
}
});
prompt.getChildren().add(btnFindAnswer);
pane.setCenter(prompt);
pane.setBottom(gridPane);
Scene scene = new Scene(pane, 550, 650);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("lab 7");
primaryStage.setScene(scene);
primaryStage.show();
}
private HBox getHbox1() {
HBox hbox = new HBox(15);
hbox.setPadding(new Insets(15, 15, 15, 15));
hbox.setAlignment(Pos.TOP_CENTER);
hbox.getStyleClass().add("hbox1");
Label lblProblem = new Label("Reverse Multiplication Table");
hbox.getChildren().add(lblProblem);
return hbox;
}
public GridPane setUpGrid() {
GridPane pane = new GridPane();
Label[][] labels = new Label[11][11];
for (int row = 0; row < 11; row++) {
for (int col = 0; col < 11; col++) {
Label l = new Label();
setUpLabel(l, col, row);
labels[row][col] = l;
pane.add(l, col, row);
}
}
return pane;
}
public void setUpLabel(final Label l, final int col, final int row) {
l.setPrefHeight(50);
l.setPrefWidth(50);
l.setAlignment(Pos.CENTER);
l.setStyle("-fx-stroke-border: black; -fx-border-width: 1;");
String a = String.valueOf(row);
String b = String.valueOf(col);
if (row == 0 || col == 0) {
l.getStyleClass().add("gridBorders");
if (row == 0) {
l.setText(b);
} else if (col == 0) {
l.setText(a);
}
} else {
l.setText(a + " * " + b);
l.getStyleClass().add("gridInside");
}
}
public List<int[]> showFactors(TextField problem) {
FactorCalculator calc = new FactorCalculator();
int number = Integer.parseInt(problem.getText());
System.out.println(number);
List<int[]> factors = calc.findFactor(number, 10);
System.out.println(factors);
return factors;
}
public static void main(String[] args) {
launch(args);
}
}
GridpaneHelper.java help gridpane node access.
package reversemultiplication;
import javafx.scene.Node;
import javafx.scene.layout.GridPane;
public class GridpaneHelper {
GridPane gridPane;
public GridpaneHelper(GridPane gridPane) {
this.gridPane = gridPane;
}
private int size() {
return gridPane.getChildren().size();
}
public int getColumnSize() {
int numRows = gridPane.getRowConstraints().size();
for (int i = 0; i < gridPane.getChildren().size(); i++) {
Node child = gridPane.getChildren().get(i);
if (child.isManaged()) {
int columnIndex = GridPane.getColumnIndex(child);
int columnEnd = GridPane.getColumnIndex(child);
numRows = Math.max(numRows, (columnEnd != GridPane.REMAINING ? columnEnd : columnIndex) + 1);
}
}
return numRows;
}
public int getRowSize() {
int numRows = gridPane.getRowConstraints().size();
for (int i = 0; i < gridPane.getChildren().size(); i++) {
Node child = gridPane.getChildren().get(i);
if (child.isManaged()) {
int rowIndex = GridPane.getRowIndex(child);
int rowEnd = GridPane.getRowIndex(child);
numRows = Math.max(numRows, (rowEnd != GridPane.REMAINING ? rowEnd : rowIndex) + 1);
}
}
return numRows;
}
public Node[] getColumnChilds(int columnNo) {
if (columnNo < getRowSize()) {
return getChildren()[columnNo];
}
return null;
}
public Node[] getRowChilds(int rowNo) {
Node n[] = new Node[getRowSize()];
if (rowNo <= getRowSize()) {
for (int i = 0; i < getRowSize(); i++) {
n[i] = getColumnChilds(i)[rowNo];
}
return n;
}
return null;
}
public Node[] getChildRowVia() {
Node n[] = new Node[size()];
int col = getColumnSize();
int arrIncre = 0;
for (int i = 0; i < col; i++) {
for (Node n1 : getRowChilds(i)) {
if (n1 != null) {
n[arrIncre] = n1;
arrIncre++;
}
}
}
return n;
}
public Node[][] getChildren() {
Node[][] nodes = new Node[getRowSize()][getColumnSize()];
for (Node node : gridPane.getChildren()) {
int row = gridPane.getRowIndex(node);
int column = gridPane.getColumnIndex(node);
nodes[row][column] = node;
}
return nodes;
}
public Integer postion(Node node, Pos pos) {
if (node != null) {
switch (pos) {
case Row:
return gridPane.getRowIndex(node);
case Column:
return gridPane.getColumnIndex(node);
}
}
return null;
}
enum Pos {
Row,
Column;
}
}
One new method added to FactorCalculator.java class file this help to how many combination are made.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package reversemultiplication;
import java.util.ArrayList;
import java.util.List;
/**
*
* #author reegan
*/
class FactorCalculator {
public List<Integer> list = new ArrayList<Integer>();
private int problem = 0;
public List<int[]> findFactor(int problem, int limit) {
int incrementer = 1;
this.problem = problem;
while (incrementer <= limit) {
if (problem % incrementer == 0) {
list.add(incrementer);
}
incrementer++;
}
return combinational();
}
public List<int[]> combinational() {
List<int[]> arrays = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < list.size(); j++) {
if (list.get(i) * list.get(j) == problem) {
int[] inx = new int[2];
inx[0] = list.get(i);
inx[1] = list.get(j);
arrays.add(inx);
}
}
}
return arrays;
}
}
add your css file in your project ,but this example code not clear in previous set style.after i will tell this.
The answer from Roland/ItachiUchiha is good: here is another approach.
Define an IntegerProperty to hold the current value:
public class Main extends Application {
private final IntegerProperty value = new SimpleIntegerProperty();
// ...
}
Now just have each label observe the value:
public void setUpLabel(final Label l, final int col, final int row) {
value.addListener((obs, oldValue, newValue) -> {
if (col * row == newValue.intValue()) {
l.getStyleClass().add("gridAnswer");
} else {
l.getStyleClass().remove("gridAnswer");
}
});
// all previous code...
}
Finally, just set the value when the button is pressed:
btnFindAnswer.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
// you probably don't need this any more:
int x = showFactors(tfProblem);
value.set(Integer.parseInt(tfProblem.getText()));
}
});
I am working on a game that my friends invented - a little variation on tic tac toe: using a 4x4 board, one player (x) need to get 3 x's in a particular manner while the other can place one 'z' and one 'o' every turn and needs to fill the entire board. My problem is not with the rules and algoritems, but with the graphics: I don't have a lot of experience with graphics, and just can't get my board to work (even without any rules - just show up as needed).
I have a Board class that represents a board. A board has a two dimensional array of Cells. Each Cell (Cell = another class of mine) is also a JButton, and I would like that every time a button is clicked his image will change - so I decided to use ImageIcon. I also have a GameMain class to control the game and a Tools class to add two buttons - 'Exit' and 'Reset'.
If you could please help me by suggesting ways to get my board to load properly, I would appreciate that. Currently the board doesn't show up at all, and if I tweak the code a bit it shows up but the buttons won't show at all.
Here's the code: GameMain.java:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class GameMain extends JPanel {
private Turn _turn;
Board _board;
private Tools _buttons;
private boolean isOver = false;
public enum GameState {PLAYING, xWON, oWON};
private GameState _currentState;
// Name-constants for the various dimensions used for graphics drawing
public static final int CELL_SIZE = 100; // cell width and height (square)
public static final int CANVAS_WIDTH = CELL_SIZE * 4; // the drawing canvas
public static final int CANVAS_HEIGHT = CELL_SIZE * 4;
public static final int GRID_WIDTH = 8; // Grid-line's width
public static final int GRID_WIDTH_HALF = GRID_WIDTH / 2; // Grid-line's half-width
public GameMain() {
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (_currentState == GameState.PLAYING) {
updateGame();
} else {
initGame(); //game over, restart
}
repaint();
}
});
setLayout(new BorderLayout());
setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT + 30));
_board = new Board();
_buttons = new Tools();
initGame();
_buttons.SetObject(_board);
add(_board, BorderLayout.CENTER);
add(_buttons, BorderLayout.SOUTH);
}
public void initGame() {
_turn = Turn.X;
_board.init();
_currentState = GameState.PLAYING;
}
public void updateGame() {
if (_board.hasWonX()) {
_currentState = GameState.xWON;
} else if (_board.hasWonO()) {
_currentState = GameState.oWON;
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
_board.paint(g);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("xBlock");
frame.setSize(500, 500);
// Set the content-pane of the JFrame to an instance of main JPanel
frame.setContentPane(new GameMain());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null); // center the application window
frame.setVisible(true); // show it
}
});
}
}
Board:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Board extends JPanel implements ActionListener {
private Cell[][] _cells;
private Turn _turn;
public Board() {
setLayout(new GridLayout(4, 4));
_cells = new Cell[4][4];
_turn = Turn.X;
for (int i = 0; i < _cells.length; i++) {
for (int j = 0; j < _cells[0].length; j++) {
_cells[i][j] = new Cell(i, j);
_cells[i][j].addActionListener(this);
add(_cells[i][j]);
}
}
}
//initiate board
public void init() {
_turn = Turn.X;
for (int i = 0; i < _cells.length; i++) {
for (int j = 0; j < _cells[0].length; j++) {
_cells[i][j].setState(State.EMPTY);
}
}
}
public void fillCell(Cell c) {
if (c.getState() == State.EMPTY) {
c.setState(_turn.ordinal());
c.setEnabled(false);
c.draw();
_turn = _turn.getNext();
}
}
public void checkCellsAround(Cell c) {
State state = c.getState();
State right, left, up, down;
if (c.getJ() < 3 && c.getJ() > 0) {
right = _cells[c.getI()][c.getJ() + 1].getState();
left = _cells[c.getI()][c.getJ() - 1].getState();
} else if (c.getJ() == 0) {
right = _cells[c.getI()][c.getJ() + 1].getState();
left = State.EMPTY;
} else {
right = State.EMPTY;
left = _cells[c.getI()][c.getJ() - 1].getState();
}
if (c.getI() < 3 && c.getI() > 0) {
up = _cells[c.getI() - 1][c.getJ()].getState();
down = _cells[c.getI() + 1][c.getJ()].getState();
} else if (c.getI() == 0) {
up = State.EMPTY;
down = _cells[c.getI() + 1][c.getJ()].getState();
} else {
up = _cells[c.getI() - 1][c.getJ()].getState();
down = State.EMPTY;
}
switch (state) {
case EMPTY:
break;
case X:
if ((left == State.O && right == State.O) || (up == State.O && down == State.O) || (left == State.Z && right == State.Z) || (up == State.Z && down == State.Z)) {
c.setState(State.HOURGLASS);
}
break;
case O:
if ((left == State.X && right == State.X) || (up == State.X && down == State.X)) {
c.setState(State.EMPTY);
}
break;
case Z:
if ((left == State.X && right == State.X) || (up == State.X && down == State.X)) {
c.setState(State.HOURGLASS);
}
break;
case HOURGLASS:
break;
case SCRIBBLE:
break;
}
}
public void actionPerformed(ActionEvent E) {
Cell c = (Cell) E.getSource();
fillCell(_cells[c.getI()][c.getJ()]);
}
public boolean hasWonO() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (_cells[i][j].getState() == State.EMPTY) {
return false;
}
}
}
return true;
}
public boolean hasWonX() {
return false;
}
public void paint(Graphics g) {
g.setColor(Color.GRAY);
for (int i = 1; i < 4; i++) {
g.fillRoundRect(0, GameMain.CELL_SIZE * i - GameMain.GRID_WIDTH_HALF,
GameMain.CANVAS_WIDTH - 1, GameMain.GRID_WIDTH,
GameMain.GRID_WIDTH, GameMain.GRID_WIDTH);
}
for (int j = 1; j < 4; j++) {
g.fillRoundRect(GameMain.CELL_SIZE * j - GameMain.GRID_WIDTH_HALF, 0,
GameMain.GRID_WIDTH, GameMain.CANVAS_HEIGHT - 1,
GameMain.GRID_WIDTH, GameMain.GRID_WIDTH);
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
_cells[i][j].draw();
}
}
}
}
Cell.java:
import javax.swing.ImageIcon;
import javax.swing.JButton;
public class Cell extends JButton {
private int _i, _j;
private State _state;
ImageIcon X = new ImageIcon(this.getClass().getResource("x-icon.png"));
ImageIcon O = new ImageIcon(this.getClass().getResource("o-icon.png"));
ImageIcon Z = new ImageIcon(this.getClass().getResource("z-icon.png"));
ImageIcon Hourglass = new ImageIcon(this.getClass().getResource("hourglass-icon.png"));
ImageIcon Scribble = new ImageIcon(this.getClass().getResource("scribble-icon.png"));
public Cell() {
this.setEnabled(true);
_i = 0;
_j = 0;
_state = State.EMPTY;
}
public Cell(int i, int j) {
this.setEnabled(true);
_i = i;
_j = j;
_state = State.EMPTY;
}
public int getI() {
return _i;
}
public int getJ() {
return _j;
}
public void setState(State state) {
_state = state;
if (state == State.EMPTY) {
this.setEnabled(true);
}
}
public void setState(int index) {
_state = State.values()[index];
}
public State getState() {
return _state;
}
public void draw() {
switch (_state) {
case EMPTY:
this.setIcon(null);
break;
case X:
this.setIcon(X);
break;
case O:
this.setIcon(X);
break;
case Z:
this.setIcon(X);
break;
case HOURGLASS:
this.setIcon(X);
break;
case SCRIBBLE:
this.setIcon(X);
break;
}
}
public void highlight() {
}
}
Tools.java:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Tools extends JPanel {
private JButton _exit, _reset;
private Board _board;
Tools() {
setLayout(new FlowLayout());
_exit = new JButton("Exit");
_reset = new JButton("Reset");
_exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
});
_reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
_board.init();
}
});
add(_exit);
add(_reset);
}
public void SetObject(Board b) {
_board = b;
}
}
State.java:
public enum State {
EMPTY, X, O, Z, HOURGLASS, SCRIBBLE;
public State getNext() {
return State.values()[(this.ordinal() + 1) % State.values().length];
}
}
Turn.java:
public enum Turn {
X, O, Z;
public Turn getNext() {
return Turn.values()[(this.ordinal() + 1) % Turn.values().length];
}
}
Thanks in advance!
So after running it, you are getting an ArrayIndexOutOfBoundsException at this line in the paint method of the Board class:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
_cells[i][j].draw(); <==========
}
}
Not sure how your game works, but by looking at the loops previous to this one, you are accessing only up to index 3 ( for (int j = 1; j < 4; j++) { ). So if you change the loop max to 4, it gets the game up and running.
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
_cells[i][j].draw();
}
}
Learning to read exceptions and stack traces is very important. It will save you a lot of future headaches. Take some time to read What is a stack trace, and how can I use it to debug my application errors?
And like I said in my comments,
It doesn't look like you're doing anything with the paintComponent in the GameMain. You should just get rid of the paintComponent method altogether in that class. Instead of trying to call board.paint(g);, try to just call board.repaint() in the mouse listener, instead of trying to repaint the main game panel. And just set the background in the constructor of the GameMain instead of in the paintComponent method.
Also in the Board class use paintComponent rather than paint. and don't forget to call super.paintComponent in the paintComponent method
Fixing all the things above, get it work (I guess).
UPDATE
As the MadMan pointed out in the comment below, it would be better to use the _cells.length to avoid having to rely magic numbers. This way you will be sure not to access an inexistant index
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
_cells[i][j].draw();
}
}