2015-02-05 1 views
2

나는이 질문을 다시 게시하여보다 정확 해지기를 바라고 있으며, 이것이 나를 미치게 만들 때 도움이되기를 희망합니다. 나는 최대 6 명의 플레이어와 보드 게임을 개발 중입니다. 각 플레이어마다 색이 다른 폰이 있습니다.Java Swing Timer and Animation : 함께 쓰는 법

다음의 BufferedImage []의 위치에 각 색의 다이의 각면을 가하고,

enter image description here

이것은 상대적인 코드 : I는 BufferedImage의 배열에 넣은 다음 이미지 스프라이트로 처리 한

private BufferedImage[] initAnimationBuffer() { 
    BufferedImage[] result = new BufferedImage[36]; 
    for (int i = 0; i < 6; i++) { 
     for (int j = i; j < 6 + i; j++) 
      result[i + j] = DieSprite.getSprite(j, i, 0); 

    } 

    return result; 
} 

각 플레이어는 자신의 색에 따라 얻은 다이 값/위치에 따라 그의 색면을 포함하는 다음 행렬을 갖습니다.

private BufferedImage[][] initExactDieFaces() { 
    BufferedImage[][] result = new BufferedImage[6][1]; 
    int row = -1; 
    String myColor = this.coreGame.getMyPartecipant().getColor(); 
    if (myColor.equals(Constants.COLOR[0])) { 
     row = 0; 
    } else if (myColor.equals(Constants.COLOR[1])) { 
     row = 2; 
    } else if (myColor.equals(Constants.COLOR[2])) { 
     row = 4; 
    } else if (myColor.equals(Constants.COLOR[3])) { 
     row = 1; 
    } else if (myColor.equals(Constants.COLOR[4])) { 
     row = 5; 
    } else if (myColor.equals(Constants.COLOR[5])) { 
     row = 3; 
    } 
    int offset = 0; 
    for (int i = 0; i < 6; i++) { 
     result[i][0] = DieSprite.getSprite(row, i, offset); 
     offset += 2; 
    } 
    return result; 
} 

내가 원하는 것은 다음과 같은 것이다 : 다시 말해서,이 매트릭스는 이미지의 "라인"을 포함하고이 값에 의해 인덱싱 는 - 언제 버튼을 누르면 "다이 플립"I가 원하는 (예를 들어 JPanel 안에있는 특정 JLabel에서 20 개의 임의의 다이 페이스가 표시됩니다 (첫 번째 배열 인 AnimationBuffer에서 가져와야 함). 이전 애니메이션이 끝나면 마침내 획득 한 결과가 die가 표시됩니다 (색 폰에 따라, ExcatDieFaces에서 가져옴).

스윙 타이머가 필요하다는 것을 알고 있지만 모두 정리할 수는 없습니다.

private void startAnimationDie(final JPanel dieContainer) { 

    final BufferedImage[] animationBuffer = initAnimationBuffer(); 
    final BufferedImage[][] exactDieFaces = initExactDieFaces(); 
    final AnimationSprite animation = new AnimationSprite(
        animationBuffer, Constants.DIE_ANIMATION_SPEED); 

    /* getting launch value fromt the core Game */ 
    int launchResult = coreGame.launchDie(); 
    coreGame.getMyPartecipant().setLastLaunch(launchResult); 

    final Timer timer = new Timer(250, new ActionListener() { 

    @Override 
    public void actionPerformed(ActionEvent e) { 

    dieContainer.removeAll(); 
    dieContainer.updateUI(); 
    animation.start(); 
    JLabel resultDie = new JLabel(); 
    resultDie.setBounds(60, 265, Constants.DIE_SIZE,Constants.DIE_SIZE); 
    resultDie.setIcon(new ImageIcon(animationBuffer[new Random().nextInt(36)])); 
    dieContainer.add(resultDie); 
    dieContainer.updateUI(); 
    updateUI(); 
    repaint(); 

    } 
    }); 

/* animation begins, rolling faces are shown each time the Timer ends*/ 
for(int i = 0; i<20; i++) 
    timer.start() 

/* showing the final face according to the pawn color and the obtained result from the launch */ 

dieContainer.removeAll(); 
dieContainer.updateUI(); 
AnimationSprite resultAnimation = new AnimationSprite(exactDieFaces[launchResult - 1], 6); 
resultAnimation.start(); 
resultAnimation.update(); 
resultDie.setIcon(new ImageIcon(exactDieFaces[launchResult - 1][0])); 
resultDie.setBounds(60, 265, Constants.DIE_SIZE, Constants.DIE_SIZE); 
dieContainer.add(resultDie); 
dieContainer.updateUI(); 
dieContainer.repaint(); 

} 

가 어떻게 작동 할 수 있습니다 : 여기에 "플립 다이"버튼을 누를 때 호출되는 startAnimationDie 방법의 일부 코드는? Swing.invokeAndWait을 사용해야한다고 생각합니다. 그러나 모든 조각들을 조합 할 수는 없습니다 ... 제발 도와 주실 수 있습니까?

+1

시작을'updateUI'를 호출하지 않음으로써, 당신의 사용자 정의보기를 설치하지 않는 한 느낀다 경계에 반복하지만 Math.random를 사용하여 다음 좋습니다.둘째, 모든 구성 요소를 제거하지 말고 레이블 ('setIcon')에 대한 다이 이미지를 업데이트하면됩니다. 셋째, 카운터를 사용하여 주어진 횟수만큼 반복 할 수있는 단일 타이머를 사용하고 다이 페이스를 업데이트합니다 ... – MadProgrammer

+0

처음 두 제안에 대해서는 괜찮습니다. 타이머에 관해서, 나는 카운터를 사용하고있다, 그렇지 않은가? 당신이 할 수 있다면, 제발 좀 더 도움을 청하십시오. –

+0

당신은'타이머 '를 20 번 시작하는데 아무 효과가 없습니다 ... 한번 시작하면 ... 당신은 '타이머 '를 일종의 루프처럼 생각해야합니다 ... – MadProgrammer

답변

5
  1. 은 당신이 생각하는 일을하지 (그리고 매우 비효율적)
  2. 은 UI 매번 다시하지 마세요, 당신이보고 설치를 다루는 경우가 아니라면, updateUI 전화를 생각하지 마십시오 이것은 시간 소모적 인 작업으로, 애니메이션을 계속 보이게하고 비틀 거리고 아마 많이 깜박 거리게 만듭니다. 대신 간단히 라벨의 속성을 업데이트하십시오.
  3. Timer을 하나 사용하여 카운터를 증가시켜 호출 횟수를 알 수 있으므로 각 틱에서 주사위 굴림과 카운터를 업데이트 할 수 있습니다. 각 반복 (틱)에, 당신은 (같은 카운터를 증가)

    Die

    (보이는 참고 - 때 뭔가를 할 필요가 루프의 일종으로 Timer

생각해 죽은 것처럼 이미지가 연속적으로 한 번 더 표시 되었기 때문에 모든 이미지를 List에 넣고 Collections.shuffle을 사용하여이 이미지를 한 번 더 볼 수 있습니다.이 작업을 세 번 더 수행하여 다른 이미지에 List을 추가해야합니다. 당신에게 24, 반복없는 시퀀스 (좋아, "수도" 당신이 호출 할 필요는 없습니다한다))

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.ImageIcon; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

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

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private BufferedImage[] dice = new BufferedImage[6]; 
     private JLabel die; 

     public TestPane() { 
      try { 
       BufferedImage img = ImageIO.read(new File("/Users/swhitehead/Documents/Die.png")); 
       int width = 377/6; 
       for (int index = 0; index < 6; index++) { 
        dice[index] = img.getSubimage(width * index, 0, width, width); 
       } 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
      setLayout(new GridBagLayout()); 
      GridBagConstraints gbc = new GridBagConstraints(); 
      gbc.gridwidth = GridBagConstraints.REMAINDER; 
      die = new JLabel(new ImageIcon(dice[0])); 
      add(die, gbc); 

      JButton roll = new JButton("Roll"); 
      add(roll, gbc); 

      roll.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        roll.setEnabled(false); 
        Timer timer = new Timer(250, new ActionListener() { 
         private int counter; 
         private int lastRoll; 
         @Override 
         public void actionPerformed(ActionEvent e) { 
          if (counter < 20) { 
           counter++; 
           lastRoll = (int)(Math.random() * 6); 
           System.out.println(counter + "/" + lastRoll); 
           die.setIcon(new ImageIcon(dice[lastRoll])); 
          } else { 
           lastDieRollWas(lastRoll); 
           ((Timer)e.getSource()).stop(); 
           roll.setEnabled(true); 
          } 
         } 
        }); 
        timer.start(); 
       } 
      }); 
     } 

     protected void lastDieRollWas(int roll) { 
      System.out.println("You rolled " + (roll + 1)); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 

    } 

} 
+0

그것은 당신의 것이 었습니다. 마음으로부터 감사합니다! 이제는 꽤 좋은 결과를 얻었습니다 :) –

+0

또 다른 질문 : 플레이어가 보드에서 움직이기 전에 롤링이 끝나기를 기다리고 싶다면 invokeAndWait()를 사용해야합니다. –

+0

아니요! 그것은 당신의 시도에 대한 예외를 던질 것입니다. 타이머를 시작하면 타이머가 중지되고 타이머를 중지하면 다시 활성화되지만 "lastDieRollWas"라고도합니다.이 작업을 수행해야합니다. To를 막을 때 그녀의 방법으로 프로그램에 압연이 멈춘 것을 알립니다. – MadProgrammer