多个摆动计时器

时间:2012-05-30 03:59:03

标签: java swing timer

我有(应该是)一个简单的问题需要解决,我对其他解决方法持开放态度。我对其他解决方案持开放态度。

问题: 我们使用java swing来显示基于回合的,基于图块的游戏的图形。我正在使用带有图标的jlabels,绝对定位。

要为动作制作动画,我使用的是一个摆动计时器,每次更新4个像素的位置,慢慢向右,向左移动精灵等。

为了实现这一目标,我正在运行一个计时器,它运行得非常好。当我试图向下移动然后向右移动时,问题出现了。

精灵向下移动,从不向右移动,如果我通过某些控制台打印观察执行,很明显两个计时器同时运行。我已经在互联网上做了相当多的挖掘工作,直到第一个计时器停止,我才能找到一种告诉摆动计时器不执行的方法,如果我试着忙 - 等到一个计时器完成(根本没有显示UI(显然是向错误方向迈出的一步)。

现在我可以完全转离计时器,或者将精灵传送到新的位置,或使用一些可怕的忙等待运动方案,但我希望某种灵魂有解决方案。

简而言之:我需要一种方法在一段时间内运行一个摆动计时器,停止它,然后然后启动一个新计时器,这样它们就不会重叠。优选地,该方法将允许每个计时器处于其自己的方法中,然后我可以一个接一个地调用这些方法。

提前感谢你提出的任何建议。

编辑:扩展示例代码。如果完整的scsse是你的建议的要求,那么我很抱歉浪费你的时间,因为完整的代码是一个野兽。这个示例代码根本不起作用,抱歉,但它应该说明这一点。

因此。我们有两个函数,每个函数都有一个运行动画循环的计时器,一个用于向下和向右对角移动,一个用于直接向下移动。

   public class TestClass {
static int counter = 0;
static int counter2 = 0;
static Timer timerC;
static Timer timerX;

public static void main(String[] args) {
    moveC();
    moveX();
}

public static void moveC() {
    int delay = 200; // milliseconds

    timerC = new Timer(delay, null);
    timerC.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            if (counter < 32) {
                counter = counter + 4;
                System.out.println("*C*");
            } else {
                timerC.stop();
                System.out.println("*C STOP*");
            }

        }
    });
    timerC.start();
}

public static void moveX() {
    int delay = 200; // milliseconds

    timerX = new Timer(delay, null);
    timerX.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            if (counter < 32) {
                counter = counter + 4;
                System.out.println("*X*");
            } else {
                timerX.stop();
                System.out.println("*X STOP*");
            }

        }
    });
    timerX.start();
}

}

我最终希望看到的是

*C*
*C*
*C*
*C*
*C STOP*
*X*
*X*
*X*
*X*
*X STOP*

我实际得到的是

*C*
*X*
*C*
*X*
*C*
*X*
*C*
*X*
*C STOP*
*X STOP*

我试图在这里得到的一点是运行一个动画周期,然后是另一个。

再次感谢。

3 个答案:

答案 0 :(得分:5)

不要使用多个计时器,而是只使用一个计时器来处理每个方向。您需要某种类型的队列来保存方向信息,无论是正式队列还是用作队列的集合(先进先出),然后让Timer在运行时从该队列中提取方向。例如,在这里我使用我的JList模型作为我的队列,删除并使用首先添加的Direction(在JList的顶部):

import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;

public class TimerPlay extends JPanel {
   private DefaultListModel directionJListModel = new DefaultListModel();
   private JList directionJList = new JList(directionJListModel);
   JButton startTimerButton = new JButton(
         new StartTimerBtnAction("Start Timer"));

   public TimerPlay() {
      ActionListener directionBtnListener = new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent actEvt) {
            String actionCommand = actEvt.getActionCommand();
            Direction dir = Direction.valueOf(actionCommand);
            if (dir != null) {
               directionJListModel.addElement(dir);
            }
         }
      };
      JPanel directionBtnPanel = new JPanel(new GridLayout(0, 1, 0, 10));
      for (Direction dir : Direction.values()) {
         JButton dirBtn = new JButton(dir.toString());
         dirBtn.addActionListener(directionBtnListener);
         directionBtnPanel.add(dirBtn);
      }

      add(directionBtnPanel);
      add(new JScrollPane(directionJList));
      add(startTimerButton);
   }

   private class StartTimerBtnAction extends AbstractAction {
      protected static final int MAX_COUNT = 20;

      public StartTimerBtnAction(String title) {
         super(title);
      }

      @Override
      public void actionPerformed(ActionEvent arg0) {
         startTimerButton.setEnabled(false);

         int delay = 100;
         new Timer(delay, new ActionListener() {
            private int count = 0;
            private Direction dir = null;

            @Override
            public void actionPerformed(ActionEvent e) {
               if (count == MAX_COUNT) {
                  count = 0; // restart
                  return;
               } else if (count == 0) {
                  if (directionJListModel.size() == 0) {
                     ((Timer)e.getSource()).stop();
                     startTimerButton.setEnabled(true);
                     return;
                  }
                  // extract from "queue"
                  dir = (Direction) directionJListModel.remove(0);
               }
               System.out.println(dir); // do movement here
               count++;

            }
         }).start();
      }
   }

   private static void createAndShowGui() {
      TimerPlay mainPanel = new TimerPlay();

      JFrame frame = new JFrame("TimerPlay");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

}

enum Direction {
   UP, DOWN, LEFT, RIGHT;
}

答案 1 :(得分:4)

作为参考,此example管理Timer的四个实例,其中两个在任何角落中悬停时运行(交错)。您可以将它与您的方法进行比较。这个相关的answer讨论了类似基于图块的游戏中的动画。

答案 2 :(得分:4)

  • 将所有Icon放入某种形式的数组

  • 创建一个具有短暂延迟的单个Swing Timer

  • 在Swing ActionListener中,从数组中取出每个`图标,从屏幕获取getBounds,将Icon移动一步

  • 重复直到达到目标。