Java Swing的定时器和动画:如何把它在一起 [英] Java Swing Timer and Animation: how to put it together

查看:325
本文介绍了Java Swing的定时器和动画:如何把它在一起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要重新张贴此questione试图再次更precise,希望我会得到一些帮助,因为这是推动我疯了。我正在开发一个棋盘游戏多达6个的球员,每一个都用不同颜色的棋子。我有一个在BufferedImage的阵列加载下面的图片把它当作一个精灵:

和这是相对code,将每个彩色骰子的每面中的位置上的的BufferedImage []:

 私人BufferedImage的[] initAnimationBuffer(){
    BufferedImage的[]结果=新的BufferedImage [36];
    的for(int i = 0;我6;;我++){
        为(中间体J =; J&10 6 + I; J ++)
            结果[I + J] = DieSprite.getSprite(J,I,0);    }    返回结果;
}

然后每个球员,按照他的颜色,西港岛线也有根据所获得的模值/位置载有他的肤色的面孔下面的矩阵。换句话说这个矩阵包含图像的线,它是由值索引

 私人BufferedImage的[] [] initExactDieFaces(){
    的BufferedImage [] []结果=新的BufferedImage [6] [1];
    INT排= -1;
    字符串myColor = this.coreGame.getMyPartecipant()的getColor()。
    如果(myColor.equals(Constants.COLOR [0])){
        排= 0;
    }否则如果(myColor.equals(Constants.COLOR [1])){
        排= 2;
    }否则如果(myColor.equals(Constants.COLOR [2])){
        行= 4;
    }否则如果(myColor.equals(Constants.COLOR [3])){
        行= 1;
    }否则如果(myColor.equals(Constants.COLOR [4])){
        排= 5;
    }否则如果(myColor.equals(Constants.COLOR [5])){
        排= 3;
    }
    INT偏移= 0;
    的for(int i = 0;我6;;我++){
        结果由[i] [0] = DieSprite.getSprite(行,我,偏移量);
        偏移+ = 2;
    }
    返回结果;
}

我要的是以下几点:
- 当炫死按钮pssed $ P $,我想这(例如)将显示20个随机模的面在一个特定的JLabel(他们应该从第一阵列,​​AnimationBuffer采取)一个JPanel里面
-as一旦previous动画完成后,我想是,所得到的发射管芯的结果示(根据色棋子,从ExcatDieFaces取)。

要得到这个我知道,我需要摆动定时器,但我不能把它放在一起;这里的startAnimationDie方法时炫死这就是所谓的一些code按钮是pressed:

 私人无效startAnimationDie(最终的JPanel dieContainer){  最终的BufferedImage [] = animationBuffer initAnimationBuffer();
  最后BufferedImage的[] [] = exactDieFaces initExactDieFaces();
  最后AnimationSprite动画=新AnimationSprite(
                    animationBuffer,Constants.DIE_ANIMATION_SPEED);  / *获取价值推出的fromt核心游戏* /
  INT launchResult = coreGame.launchDie();
  coreGame.getMyPartecipant()setLastLaunch(launchResult)。  最后定时器定时器=新定时器(250,新的ActionListener(){  @覆盖
  公共无效的actionPerformed(ActionEvent的五){     dieContainer.removeAll();
     dieContainer.updateUI();
     animation.start();
     JLabel的resultDie =新的JLabel();
     resultDie.setBounds(60,265,Constants.DIE_SIZE,Constants.DIE_SIZE);
     resultDie.setIcon(新的ImageIcon(animationBuffer [新随机()nextInt(36)。]));
     dieContainer.add(resultDie);
     dieContainer.updateUI();
     的updateUI();
     重绘();    }
  });/ *动画开始,轧面显示的每个定时器结束时间* /
的for(int i = 0; I< 20;我++)
  timer.start()/ *表示根据从发射*棋子颜色和所获得的结果的最后面/dieContainer.removeAll();
dieContainer.updateUI();
AnimationSprite resultAnimation =新AnimationSprite(exactDieFaces [launchResult - 1],6);
resultAnimation.start();
resultAnimation.update();
resultDie.setIcon(新的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,这是耗时的工作,这将会使动画看起来平息交错,可能出现很多。相反,只需更新标签的图标属性

  3. 使用一个定时,允许它增加一个计数器,所以你知道它有多少次被调用和更新的模具辊和柜台上的每一跳。

想到的定时作为一种循环,在每次迭代(打勾),你需要做的事情(如增加计数器)

(注意:当它看起来像模具已陷入僵局,这是因为图像序列被显示更多然后一次。您可以通过所有的图像将成为列表<上走到这一步/ code>,并使用 Col​​lections.shuffle 。做这个的三倍,增添结果到另一个列表应给你24,无重复序列(好吧,这可能重复上的界限,但它是更好然后使用的Math.random ;))

 进口java.awt.Dimension中;
进口java.awt.EventQueue中;
进口java.awt.GridBagConstraints中;
进口java.awt.GridBagLayout中;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口java.awt.image.BufferedImage中;
进口的java.io.File;
进口java.io.IOException异常;
进口javax.imageio.ImageIO中;
进口javax.swing.ImageIcon中;
进口javax.swing.JButton中;
进口javax.swing.JFrame中;
进口javax.swing.JLabel中;
进口javax.swing.JPanel中;
进口javax.swing.Timer中;
进口javax.swing.UIManager中;
进口javax.swing.UnsupportedLookAndFeelException;公共类的测试{    公共静态无效的主要(字串[] args){
        新的测试();
    }    公开测试(){
        EventQueue.invokeLater(新的Runnable(){
            @覆盖
            公共无效的run(){
                尝试{
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                }赶上(ClassNotFoundException的| InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException前){
                    ex.printStackTrace();
                }                JFrame的帧=新的JFrame(测试);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(新TestPane());
                frame.pack();
                frame.setLocationRelativeTo(NULL);
                frame.setVisible(真);
            }
        });
    }    公共类TestPane继承JPanel {        私人BufferedImage的[] =骰子新的BufferedImage [6];
        私人JLabel的模具;        公共TestPane(){
            尝试{
                IMG的BufferedImage = ImageIO.read(新文件(/用户/ swhitehead /文件/ Die.png));
                INT宽度=六分之三百七十七;
                对于(INT指数= 0;指数6;;指数++){
                    骰子[指数] = img.getSubimage(宽*指数,0,宽度,宽度);
                }
            }赶上(IOException异常前){
                ex.printStackTrace();
            }
            的setLayout(新的GridBagLayout());
            GridBagConstraints的GBC =新的GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            死亡=新的JLabel(新的ImageIcon(骰子[0]));
            加(死,GBC);            JButton的滚动=新的JButton(滚);
            加(卷,GBC);            roll.addActionListener(新的ActionListener(){
                @覆盖
                公共无效的actionPerformed(ActionEvent的五){
                    roll.setEnabled(假);
                    定时器定时器=新定时器(250,新的ActionListener(){
                        私人诠释柜台;
                        私人诠释lastRoll;
                        @覆盖
                        公共无效的actionPerformed(ActionEvent的五){
                            如果(计数器&LT; 20){
                                反++;
                                lastRoll =(int)的(的Math.random()* 6);
                                的System.out.println(计数器+/+ lastRoll);
                                die.setIcon(新的ImageIcon(骰子[lastRoll]));
                            }其他{
                                lastDieRollWas(lastRoll);
                                ((定时器)e.getSource())停止();
                                roll.setEnabled(真);
                            }
                        }
                    });
                    timer.start();
                }
            });
        }        保护无效lastDieRollWas(INT卷){
            的System.out.println(你滚+(卷+ 1));
        }        @覆盖
        公共尺寸的get preferredSize(){
            返回新尺寸(200,200);
        }    }}

I am gonna re-post this questione again trying to be more precise and hoping I will get some help because this is driving me crazy. I am developing a board game with up to 6 player, each one with a different colored pawn. I have the following image that is loaded in BufferedImage arrays treating it as a sprite:

and this is the relative code, putting each face of each colored die in a position in the 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;
}

Then each player, according to his color, wil have also the following matrix containing the faces of his color according to the obtained die value/position. In other words this matrix contains "a line" of the image and it is indexed by value:

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

What I want is the following: -when the "flip die" button is pressed, I want that (for example) 20 random die faces are shown (they should be taken from the first array, AnimationBuffer) in a specific JLabel inside a JPanel -as soon as the previous animation has finished, I want that the obtained result of the launch of the die is shown (according to the color pawn, taken from ExcatDieFaces).

To get this I know that I need Swing Timer but I am not able to put it all together; here's some code of the startAnimationDie method which is called when the "flip die" button is pressed:

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

}

How can I make it work? I think I am supposed to use Swing.invokeAndWait but I cannot put together all the pieces...Can you help please?

解决方案

  1. Don't call updateUI, unless you're dealing with installing a look and feel, it's not doing what you think it is (and it's very inefficient)
  2. Don't rebuild the UI each time, this is time consuming work, which is going to make the animation look stilled and staggered and probably flash a lot. Instead, simply update the icon property of the label
  3. Use a single Timer, allow it to increment a counter, so you know how many times it's been called and update the die roll and counter on each tick.

Think of the Timer as a kind of loop, where on each iteration (tick), you need to do something (like increment the counter)

(Note- When it looks like the die has "stalled", it's because the image is been displayed more then once in sequence. You could over come this by placing all the images into a List and using Collections.shuffle. Do this three times, adding the result to another List should give you 24, no-repeating sequence (ok, it "might" repeat on the boundaries, but it's better then using 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);
        }

    }

}

这篇关于Java Swing的定时器和动画:如何把它在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆