2014-12-19 9 views
6

기본적으로 게임 인 자바 프로그램이 있습니다. 이 클래스에는 'World'이라는 클래스가 있습니다. "월드"클래스는 'levelChanger()'이고 다른 메서드는 'makeColorArray()'입니다.하나의 스레드가 다른 스레드에서 사용중인 배열을 수정하는 것을 중지하려면 어떻게합니까?

public class World { 

    private BufferedImage map, map1, map2, map3; 
    private Color[][] colorArray; 

    public World(int scrWd, int scrHi) { 
     try { 
      map1 = ImageIO.read(new File("map1.png")); 
      map2 = ImageIO.read(new File("map2.png")); 
      map3 = ImageIO.read(new File("map3.png")); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     map = map1; 

     makeColorArray(); 
    } 

    private void makeColorArray() { 
     colorArray = new Color[mapHi][mapWd]; // resetting the color-array 
     for(int i = 0; i < mapHi; i++) { 
      for(int j = 0; j < mapWd; j++) { 
       colorArray[i][j] = new Color(map.getRGB(j, i)); 
      } 
     } 
    } 

    //color-array used by paint to paint the world 
    public void paint(Graphics2D g2d, float camX, float camY) { 
     for(int i = 0; i < mapHi; i++) { 
      for(int j = 0; j < mapWd; j++) { 
       if(colorArray[i][j].getRed() == 38 && colorArray[i][j].getGreen() == 127 && colorArray[i][j].getBlue() == 0) { 
        //draw Image 1 
       } 
       else if(colorArray[i][j].getRed() == 255 && colorArray[i][j].getGreen() == 0 && colorArray[i][j].getBlue() == 0) { 
        //draw Image 2 
       } 
      } 
     } 
    } 

    public void levelChanger(Player player, Enemies enemies) { 
     if(player.getRec().intersects(checkPoint[0])) { 
      map = map2; 
      //calls the color-array maker 
      makeColorArray();   
     } 
     else if(player.getRec().intersects(checkPoint[1])) { 
      map = map3; 
      makeColorArray(); 
     } 
    } 

    public void update(Player player, Enemies enemies) { 
     levelChanger(player, enemies); 
    } 
} 

makeColorArray() 메소드는 '색상' 유형의 2D 배열을 만든다. 이 배열은 PNG 이미지의 Color 객체를 저장합니다. 이 배열은 JPanel의 paint() 메서드에서 화면에 세계를 칠하는 데 사용됩니다.

levelChanger() 메서드는 특정 코드 작업이 true 일 때 게임의 레벨 (스테이지)을 변경하는 데 사용됩니다. 이 makeColorArray() 메서드를 호출하여 게임 레벨을 변경하는 동안 색상 배열을 다시 만드는 방법입니다.

문제는 스레드에서 실행되는 게임 루프가 있다는 것입니다. 이제 JPanel과 같은 스윙 구성 요소의 페인팅은 Java에 의해 다른 배경 스레드에서 수행됩니다. 게임 레벨이 변경되면 색상 배열 객체가 다시 만들어집니다. 이제까지 말했던 것처럼, 색상 배열 객체는 paint() 메서드에 의해 화면에 세계를 칠하는 데 사용됩니다. 게임 논리에 따라 색상 배열 객체가 다시 만들어지고 해당 멤버가 null로 설정되면 배경 배열 스레드 (아직 완료되지 않은 그림)에서 색상 배열 객체가 사용되는 경우가 있습니다. 이로 인해 널 포인터 예외 가끔 발생합니다. 분명히 경쟁 조건.

백그라운드 스윙 스레드가 페인팅을 완료 할 때까지 게임 배열이 색상 배열을 재설정하지 못하게하려면 어떻게해야합니까?

+1

Java 동시성 라이브러리를 살펴 보는 것이 좋습니다. http://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html – dckuehn

+0

최상의 솔루션은 다중 스레드를 사용하지 않는 것입니다. 메인 루프를'javax.swing.Timer'로 바꾸거나'SwingUtilities.invokeAndWait'를 사용하십시오. –

+0

@Banthar는 문제에 대한 간단한 해결책이지만 모든 경우에있어서 최선은 아닙니다. 업데이트 코드가 처리하는 데 시간이 오래 걸리면 EDT로 이동하면 실제 UI 이벤트가 반응적이고시기 적절하게 처리되지 않습니다. – NESPowerGlove

답변

1

제안 :

  • 사용하여 프로그램에 대한 모델 - 뷰 - 컨트롤 디자인, 또는 많은 유사한 변종 중 하나를 사용

    이 게시물을 참조하십시오.
  • 스윙 타이머를 사용하여 GUI 게임 루프를 구동하지만 모델의 타이머 지연이 아닌 실시간 슬라이스를 사용하여 루프 단계 간의 시간 길이를 결정하십시오.
  • 모델은 GUI 스윙 이벤트 스레드에서 실행해야합니다.
  • 그러나 장기 실행 작업은 SwingWorker를 사용하여 백그라운드 스레드에서 실행해야합니다.
  • 이것은 중요합니다 : 백그라운드 스레드가 작업을 완료 할 때까지 모델의 데이터, JPanel에서 그리는 데 사용되는 데이터를 업데이트하지 않습니다. PropertyChangeListener 및 SwingPropertyChangeSupport가 이것에 도움이됩니다.
  • JPanel은 paint(...) 메서드가 아니라 paintComponent(...) 메서드를 사용하고 super 메서드를 호출해야합니다.
  • 배경 이미지를 BufferedImage로 만들고 효율성을 높이기 위해 paintComponent(...) 방법으로 JPanel을 그리는 것이 가장 좋습니다.
  • repaint() 호출을 제외한 모든 Swing GUI 코드가 Swing 이벤트 스레드에서 호출되는지 확인하십시오.
  • 그리고 예, 확실히 Concurrency in Swing tutorial을 읽어보십시오.
1

최소한의 변경으로 한 가지 방법은 색상 배열에 대한 액세스를 동기화하는 것입니다.

나는 개별적으로 공유 된 데이터를 개별 스레드에 추상화하여 완전히 스레드로부터 안전합니다. 그러면 코드베이스의 두 부분으로 나뉘어져있는 부분을 확인해야 할 필요가 없습니다. 언뜻보기에지도를 다루는 것 이상의 수업을하는 것 같습니다. 아마도 제가 설명하는 그런 수업 일 것입니다.)

private void makeColorArray() { 
    Color[][] colorArrayTemp = new Color[mapHi][mapWd]; // resetting the color-array 
    for(int i = 0; i < mapHi; i++) { 
     for(int j = 0; j < mapWd; j++) { 
      colorArrayTemp [i][j] = new Color(map.getRGB(j, i)); 
     } 
    } 
    synchronized(colorArray) 
    { 
     colorArray = colorArrayTemp; 
    } 
} 

//color-array used by paint to paint the world 
public void paint(Graphics2D g2d, float camX, float camY) { 
    synchronized(colorArray) 
    { 
     for(int i = 0; i < mapHi; i++) { 
      for(int j = 0; j < mapWd; j++) { 
       if(colorArray[i][j].getRed() == 38 && colorArray[i][j].getGreen() == 127 && colorArray[i][j].getBlue() == 0) { 
        //draw Image 1 
       } 
       else if(colorArray[i][j].getRed() == 255 && colorArray[i][j].getGreen() == 0 && colorArray[i][j].getBlue() == 0) { 
        //draw Image 2 
       } 
      } 
     } 

    } 
} 
관련 문제