3

I recently have been learning JavaFX and have an issue about how to refresh the pane. In this simple program, I want the black square to move to the right into the next block when I am clicking the move button, but it doesn't work, I'm wondering how can I fix my code.

screen shot

Main Class:

public class Main extends Application {
    private Cell cells[] = new Cell[5];
    private Player player;
    private Board board;
    Button move = new Button("move");

    public Main() throws Exception {
        for (int i = 0; i < cells.length; i++) {
            cells[i] = new Cell(i);
        }
        this.player = new Player(0, cells);
        this.board = new Board(player, cells);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Main game = new Main();
        BorderPane pane = new BorderPane();
        pane.setCenter(board);
        pane.setBottom(move);

        Scene scene = new Scene(pane,400,80);
        primaryStage.setTitle("Move");
        primaryStage.setScene(scene); 
        primaryStage.show();

        move.setOnAction(e -> game.move());
    }
    public void move() {
        player.currentCell.index += 1;
        board.paint();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

Board class:

class Board extends Pane {
    private Player player;
    public Cell cells[];
    private final int CELLWIDTH = 40;
    private final int CELLHEIGHT = 40;
    private final int LMARGIN = 100;

    public Board(Player p, Cell cells[]) {
        player = p;
        this.cells = cells;
        paint();
    }

    public void paint() {
        Cell cell;
        for (int i=0; i<cells.length; i++) {
            cell = cells[i];
            Rectangle r1 = new Rectangle(xCor(cell.index), 0, CELLWIDTH, CELLHEIGHT); 
            r1.setStroke(Color.BLACK); 
            r1.setFill(Color.WHITE);
            getChildren().add(r1);
        }

        cell = player.currentCell;
        Rectangle r2 = new Rectangle(xCor(cell.index), 0, CELLWIDTH, CELLHEIGHT); 
        r2.setFill(Color.BLACK);
        getChildren().add(r2);
    }
    private int xCor(int col) {
        return LMARGIN + col * CELLWIDTH;
    }
}

Player Class:

class Player {
    public int position;
    public Cell currentCell;
    public Player(int position, Cell cell[]) throws Exception {
        this.currentCell = cell[0];
    }
}

Cell Class:

class Cell {
    public int index;
    public Cell(int index) {
        this.index = index;
    }
}
Draken
  • 3,134
  • 13
  • 34
  • 54
Chen
  • 147
  • 1
  • 1
  • 11
  • Did you check the code I posted, did that solve your issue? – Draken Apr 20 '16 at 11:28
  • 1
    Why do you create a second instance of `Main`? Shcould be `move.setOnAction(e -> this.move());` Also you are adding more and more `Rectangle`s to the `Board`, but never remove them. Is that on purpose? – fabian Apr 20 '16 at 17:03
  • Updated the answer and got it working on mine, hope that helps – Draken Apr 21 '16 at 07:42

1 Answers1

2

You might want to reword your code, storing the player's location just in the Player class is going to make life difficult. I would also suggest adding a flag to the Cell class stating if the player is inside, e.g.

class Cell {
    public int index;
    private Player playerInCell;
    public Cell(int index) {
        this.index = index;
    }
    public void setPlayerInCell(Player p){
        this.playerInCell = p;
    }
    public void clearPlayerInCell(){
        this.playerInCell = null;
    }
    public Player getPlayerInCell(){
        return this.playerInCell;
    }
}

Then, upon moving a player to the Cell you can clear them from the previous Celland set them in the new one and in your Paint() function, if player is present, colour the cell in.

The other thing, if you wish to stick with your method, your issue is caused by that you are only changing the index property on the Cell class, you should also be either changing the Cell's position in the array cells[] or just changing the currentCell property of the Player class, otherwise your player always stays in the same place. Here is an example of changing the Player's currentCell property:

public void move() {
    Cell currentCell = player.currentCell;
    Cell nextCell = null;
    for (int i = 0; i < cells.length; i++) {
        if (cells[i] == currentCell && i+1 < cells.length){
            nextCell = cells[i+1];
            break;
        }
    }
    if (nextCell != null)
        player.currentCell = nextCell;
    else{
        //Error handling, next cell not found
    }
    board.paint();
}

[Edit]

I've done some major code cleanup, some of the ways you were doing things was a bit odd, I hope you don't mind, here are the classes that changed:

Main

public class Main extends Application {

    private Cell cells[] = new Cell[5];
    private Player player;
    private Board board;
    Button move = new Button("move");

    public Main() throws Exception{
        for (int i = 0; i < cells.length; i++) {
            cells[i] = new Cell(i);
        }
        this.player = new Player(cells[0]);
        this.board = new Board(player, cells);
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        BorderPane pane = new BorderPane();
        pane.setCenter(board);
        pane.setBottom(move);

        Scene scene = new Scene(pane,400,80);
        primaryStage.setTitle("Move");
        primaryStage.setScene(scene);
        primaryStage.show();

        move.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                move();
            }
        });
    }

    public void move() {
        //Get current players cell, we want to move them one right
        Cell currentCell = player.getCurrentCell();
        Cell nextCell = null;
        //Searching for current cell in board, if found we need to clear the player from it and select the next cell
        for (int i = 0; i < cells.length; i++) {
            if (cells[i] == currentCell && i+1 < cells.length){
                cells[i].clearPlayerInCell();
                nextCell = cells[i+1];
                break;
            }
        }
        //We found it, let's move the player
        if (nextCell != null) {
            player.setCurrentCell(nextCell);
            nextCell.setPlayerInCell(player);
        }
        //We didn't find it, or our index was out of range, what do we do now?
        else{
            //Error handling, next cell not found
            //Example, let's put them back at the start
            player.setCurrentCell(cells[0]);
            cells[0].setPlayerInCell(player);
            cells[cells.length-1].clearPlayerInCell();
        }
        board.paint();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Board

public class Board extends Pane {
    private Player player;
    private Cell cells[];
    private final int CELLWIDTH = 40;
    private final int CELLHEIGHT = 40;
    private final int LMARGIN = 100;

    public Board(Player p, Cell cells[]) {
        player = p;
        this.cells = cells;
        paint();
    }

    public Cell[] getCells(){
        return this.cells;
    }

    public Player getPlayer() {
        return player;
    }

    public void paint() {
        //Clear previous cells, we don't need them now
        getChildren().clear();
        //Redraw them
        for(Cell cell : cells){
            Rectangle r1 = new Rectangle(xCor(cell.getIndex()), 0, CELLWIDTH, CELLHEIGHT);
            r1.setStroke(Color.BLACK);
            //We've found a player in the cell, let's colour it black
            if (cell.getPlayerInCell() != null)
                r1.setFill(Color.BLACK);
            //No, player in this cell, white it is
            else
                r1.setFill(Color.WHITE);
            getChildren().add(r1);
        }
    }
    private int xCor(int col) {
        return LMARGIN + col * CELLWIDTH;
    }
}

Player

public class Player {
    private Cell currentCell;
    public Player(Cell cell) throws Exception {
        this.currentCell = cell;
        cell.setPlayerInCell(this);
    }
    public Cell getCurrentCell(){
        return this.currentCell;
    }

    public void setCurrentCell(Cell cell){
        this.currentCell = cell;
    }
}

Cell

public class Cell {
    private int index;
    private Player playerInCell;
    public Cell(int index) {
        this.index = index;
    }
    public void setPlayerInCell(Player p){
        this.playerInCell = p;
    }
    public void clearPlayerInCell(){
        this.playerInCell = null;
    }
    public Player getPlayerInCell(){
        return this.playerInCell;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

That now works and I can move the cell along, I've also set it so that the cell goes back to the beginning if the player reaches the end, but that's an example. It works off using the Cell property of playerInCell, if that isn't null then we know a player is in the cell and can colour it black. If it is null, no player is in the cell and we can colour it white. This also allows you in the future to maybe have more players with different colours. Though I don't know what your end goal is. Hope this helps and if you want any further explanation, feel free to ask

Also, for further reading, see here why it's better to use getter and setters like I have

Also, the reasoning behind this bit of code:

move.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent actionEvent) {
        move();
    }
});

Is because I'm using Java 1.7 instead of Java 1.8 and can't use predicates, you should be safe to change that to move.setOnAction(e -> this.move()); instead.

Community
  • 1
  • 1
Draken
  • 3,134
  • 13
  • 34
  • 54