2014-08-30 2 views
1

편집 : 답변 발견! CAG가 올바른 방향으로 나를 설득 시켰지만 그에 대한 보상을 할 것입니다. 그래도 정답은 나에게 제공된다.JavaFX Snake Thread.Sleep()이 FXML을로드하지 않습니다.

저는 Canvas를 사용하여 JavaFX에서 Snake 게임을 만들고 있습니다.

  1. 인쇄 올바른 VBox의 세포의 배경 색상을 설정하여 그리드의 시각적 표현 :

    나는 while 루프에서 실행되는 게임이있다. 입력

  2. 기다립니다 (Thread.sleep를 (1000).
  3. 다음 시각적 효과를 생성 할 수 있습니다.

을 문제는 내가 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); 
    } 
} 
+0

정확하게'Thread.sleep()'을 사용하고 있습니까? 질문을 뒷받침 할 수있는 코드를 게시 할 수 있습니까? – ItachiUchiha

+0

@ItachiUchiha가 추가되었습니다. –

답변

1

내 생각 엔 당신이 FX 응용 프로그램 스레드에 Thread.sleep()를 호출 할 수 있습니다. 이 스레드는 UI를 반응 적으로 유지할 책임이 있기 때문에 잠자기 상태로 만드는 것은 UI를 고정시키면서 게임 메카닉을 반응 형 상태로 유지합니다 (FX 응용 프로그램 스레드에서 실행 된 것으로 가정).

이 솔루션과 같이, 새로운 Thread에 게임 루프를 수행하는 것입니다 : 당신이 어떤 장기 실행 작업을 실행하거나에 잠을 호출하지 않는 한

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 응용 프로그램 스레드.

+0

사실, clearGrid() 및 printGrid()는 JavaFX UI를 수정합니다. generateNextGrid()는 내부 게임의 부울 [] []을 수정합니다. 내부 게임 논리에서 Thread.sleep을 사용하는 코드 주위에서 Thread 또는 Runnable을 사용해야합니까? 또한 platform.runLater는 무엇입니까? –

+0

runLater 메서드는 다른 스레드에서 작업 할 때 UI를 수정하는 메서드를 호출 할 때 수행해야하는 FX 응용 프로그램 스레드에서 실행될 Runnable을 보냅니다. 그래서 간단하게 generateNextGrid() 및 printGrid() 위의 내 대답을 전환하십시오. –

+0

코드가 백그라운드에서 실행되는 동안 나는 처음에는 아무것도 끝내지 않을 것입니다. 그것은 잠이 제대로 부름 받고 있지만 FXML 요소는 보이지 않는다고 알려줍니다. 코드가 업데이트되었습니다. –

1

알아 냈어! JavaFX의 동시 패키지를 사용하고 단순히 Thread 대신 Task를 사용해야했습니다.

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(); 
+0

흥미 롭습니다. 게임 루프 스레드의 오버라이드 된'start()'메소드에있는 논리를'Runnable'의 새로운 인스턴스로 리팩토링하여이를 스레드에 전달하면 호기심에서 비슷한 개선점을 얻을 수 있습니까? 'Boolean' 타입의'Task'가 오버라이드 된'call()'메소드가'Object'를 리턴합니다. –

관련 문제