JavaFX Snake Thread.Sleep()不加载FXML

时间:2014-08-30 06:31:03

标签: javafx javafx-8 thread-sleep

编辑:找到答案!尽管CAG确实让我走上正轨,但我会奖励他。我提供了正确的答案。

我正在使用Canvas在JavaFX中制作Snake游戏。

我让游戏在一个循环中运行:

  1. 通过设置打印网格的可视化表示 正确的VBox细胞的背景颜色。
  2. 等待输入(Thread.sleep(1000)。
  3. 生成下一个视觉效果。
  4. 问题是,如果我使用Thread.sleep(),我的画布根本不会加载。然而,在幕后,游戏仍在运行,直到我撞墙而死。

    我在这里做错了吗? thread.sleep()是否暂停了加载和显示JavaFX节点的能力?

        Thread gameThread = new Thread() {
    
            @Override
            public synchronized void start() {
                super.start();
                printGridToGUI();
                while (KEEP_PLAYING) {
                    generateNextGrid();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(SnakeGUIController.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    Platform.runLater(() -> {
                        printGridToGUI();
                    });
                }
                /*Stop continuing to play. You either won or lost.*/
                if (WON_GAME) {
                    System.out.println("Congratulations!");
                } else {
                    System.out.println("You lose.");
                }
            }
        };
        gameThread.start();
    

    其中printGrid()是:

    /**
     * Prints the grid, with chars in place of on and off areas.
     */
    public void printGridToGUI() {
        resetCanvas();
        for (Coordinate c : coordinates) {
            drawCell(c.row, c.col, true);
        }
        drawCell(food.row, food.col, true);
    }
    

    和resetCanvas是:

    /**
     * Clears the boolean array, setting all values to false. A quick way to
     * wipe the grid.
     */
    public final void resetCanvas() {
        /*Lay out the grid on the canvas.*/
        GraphicsContext gc = canvas.getGraphicsContext2D();
        for (int row = 0; row < GRID_SIZE; row++) {
            for (int col = 0; col < GRID_SIZE; col++) {
                drawCell(row, col, false);
            }
        }
    }
    

    和drawCell是:

    /**
     * Draws a cell on the canvas at the specified row and col. The row, col
     * coordinates are translated into x,y coordinates for the graphics context.
     *
     * @param row The row of the cell to paint.
     * @param col The col of the cell to paint.     
     * @param cellON The state of the cell, if it is on or off.
     */
    private void drawCell(int row, int col, boolean cellON) {
        /*Translate the row, col value into an x-y cartesian coordinate.*/
        int xCoord = 0 + col * CELL_SIZE;
        int yCoord = 0 + row * CELL_SIZE;
        /*Draw on the canvas.*/
        GraphicsContext gc = canvas.getGraphicsContext2D();
        gc.setFill(Color.BLACK);
        gc.fillRect(xCoord, yCoord, CELL_SIZE, CELL_SIZE);
        if (!cellON) {
            gc.setFill(Color.WHITE);
            int BORDER = 1;
            gc.fillRect(xCoord + BORDER, yCoord + BORDER, CELL_SIZE - BORDER, CELL_SIZE - BORDER);
        }
    }
    

2 个答案:

答案 0 :(得分:1)

我的猜测是你在FX应用程序线程上调用Thread.sleep()。该线程负责保持您的UI响应,因此使其处于睡眠状态会冻结您的UI,同时让您的游戏机制处于响应状态(假设这些是从FX应用程序线程执行的)。

解决方案是在新线程中执行游戏循环,如下所示:

Thread gameLoop = new Thread(() ->
{
     while (KEEP_PLAYING)
     {
         printGrid(); //<- I assume this prints the state of the grid to the console, and so is safe to execute off of the FX Application Thread
         try
         {
             Thread.sleep(1000);
         }
         catch (InterruptedException ex) {}
         Platform.runLater(() ->
         {
             generateNextGrid(); //<- execute this on the FX Application Thread as it modifies your UI
         });
     }
     if (WON_GAME)
     {
         ...
     }
     else
     {
         ...
     }
});
gameLoop.start();

这可以防止任何冻结,只要您没有执行任何长时间运行的任务或在FX应用程序线程上调用睡眠。

答案 1 :(得分:1)

想出来!我不得不使用JavaFX的并发包并利用Task而不是简单的Thread。

    Task<Boolean> gameTask = new Task() {

        @Override
        protected Object call() throws Exception {
            while (KEEP_PLAYING) {
                generateNextGrid();
                try {
                    Thread.sleep(GAME_SPEED_DELAY);
                } catch (InterruptedException ex) {
                    Logger.getLogger(SnakeGUIController.class.getName()).log(Level.SEVERE, null, ex);
                }
                Platform.runLater(() -> printGridToGUI());
            }
            /*Stop continuing to play. You either won or lost.*/
            if (WON_GAME) {
                System.out.println("Congratulations!");
            } else {
                System.out.println("You lose.");
            }
            return true;
        }
    };
    Thread gameThread = new Thread(gameTask);
    gameThread.start();