Java Swing Timer和Animation:如何将它组合在一起

我将再次发布这个问题,试图更精确,并希望我会得到一些帮助,因为这让我发疯。 我正在开发一款最多有6名玩家的棋盘游戏,每个玩家都有不同颜色的棋子。 我有下面的图像加载在BufferedImage数组中,将其视为精灵:

在此处输入图像描述

这是相对代码,将每个彩色模具的每个面放在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; } 

我想要的是以下内容: – 当按下“翻转模具”按钮时,我想要(例如)在JPanel内的特定JLabel中显示20个随机模具面(它们应该从第一个数组,AnimationBuffer中获取) – 上一个动画完成后,我想要显示所获得的骰子发射结果(根据颜色典当,取自ExcatDieFaces)。

为了得到这个,我知道我需要摆动计时器,但我无法将它们全部放在一起; 这里是startAnimationDie方法的一些代码,当按下“翻转模具”按钮时调用它:

 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(); } 

我怎样才能使它工作? 我想我应该使用Swing.invokeAndWait但是我不能把所有的东西拼凑起来……你能帮忙吗?

  1. 不要调用updateUI ,除非你正在处理安装外观和感觉,它不是你想的那样(并且效率非常低)
  2. 不要每次重建UI,这是耗时的工作,这将使动画看起来平静和交错并且可能会闪现很多。 相反,只需更新标签的icon属性即可
  3. 使用一个Timer ,允许它递增一个计数器,这样你就可以知道它被调用了多少次,并在每次滴答时更新模具滚动和计数器。

Timer视为一种循环,在每次迭代(tick)中,你需要做一些事情(比如递增计数器)

死

(注意 – 当模具看起来像“停滞”时,这是因为图像按顺序显示了一次以上。你可以通过将所有图像放入List并使用Collections.shuffle来实现这一点。这样做三次,将结果添加到另一个List应该给你24个,没有重复的序列(好吧,它“可能”在边界上重复,但它最好使用Math.random ;))

 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); } } }