当前位置: 首页 > 面试题库 >

Java Swing计时器和动画:如何将其组合在一起

百里骏
2023-03-14
问题内容

我将再次发布此问题,以使其更加精确,希望我能得到一些帮助,因为这使我发疯。我正在开发一个
最多可容纳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中获取的彩色棋子)。

要了解这一点,我知道我需要Swing计时器,但是我无法将它们全部放在一起。这是startAnimationDie方法的一些代码,
当按下“ flip die”按钮时会调用该代码:

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视为一种循环,在每次迭代(滴答)中,您
    需要做一些事情(例如增加计数器)

(注意-当模具看起来已经“停滞”时,是因为图像显示的顺序要多于一次。您可以通过将所有图像放入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);
        }

    }

}


 类似资料:
  • 问题内容: 我正在尝试为JPanel的右上角到左下角的2个框设置动画。对于动画,我使用了Swing Timer和。问题是当我单击开始按钮时。它仅设置动画并移动蓝色框,而不移动红色框。 这是代码: 问题答案: 因此,所有在类级别声明的变量都是共享的。您的第一个调用将设置它们,然后第二个调用将完全覆盖以前的值。您需要将它们从类变量更改为动画的参数。 创建一个新类,该类实现并保存该类中的变量。 例如,

  • 如何像这样创建 在问答游戏中,每一关,这个都会倒计时时间,选择答案越快,得分越高。因此,第一件事是如何获得这个上的时间。

  • 问题内容: 有没有一种快速的方法来将一个数组的值组合为另一个数组的键? 输入: 预期产量: 我该怎么办? 问题答案: 会完全按照您的意愿做。 引用手册: 通过将keys数组中的值用作键,并将values数组中的值用作对应值来创建数组。 对于您的情况,您必须执行以下操作: 当然,您也可以使用各种循环组合来做到这一点,这可能是最简单的解决方案。

  • 问题内容: 有人可以教我如何使用a 来达到以下目的: 当我单击鼠标时,我需要一个开始动画的多边形(例如旋转等简单动画);当我再次单击时停止动画。 我对理解工作方式没有任何问题,但对于实际的动画来说,没有任何问题。我尝试在方法中用while块模拟动画,在该方法中我将绘制,擦除和重绘多边形(例如,模拟旋转),但是在while内,applet不会监听点击。它只会在片刻之后收听。单击鼠标时,我需要摆动计时

  • 我在Swing和设置角色动画方面有一些问题,我有一个带有关键侦听器的JFrame,当用户点击时,它在这里调用我的JPanel方法 这个动画我的角色,但这么快,我们可以看到一个东西,我怎么才能看到动画?

  • 问题内容: 我的dao页面正在从两个不同的字段接收日期和时间,现在我想知道如何将这些日期和时间合并到一个对象中,以便我计算时差和总时间。我有要合并的这段代码,但是它在我在此代码中做错的工作不起作用,请帮助。 问题答案: 您只需要使用正确的方法,而不是调用构造函数即可。使用创建本地日期和本地时间对象,那么这两个对象传递给方法: 编辑 显然,您需要组合两个对象而不是2个字符串。我想您可以先使用将两个日