3

我有(应该是什么)一个简单的问题要解决,我愿意接受其他方法来解决它。我对其他解决方案持开放态度。

问题:我们正在使用 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*

我在这里试图达到的目的是运行一个动画周期以完成,然后是另一个。

再次感谢。

4

3 回答 3

6

不要使用多个 Timer,而是只使用一个 Timer 来根据需要处理每个方向。您需要某种类型的队列来保存方向信息,可以是正式队列,也可以是用作队列的集合(先进先出),然后让您的 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;
}
于 2012-05-30T04:45:48.773 回答
5

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

于 2012-05-30T04:18:40.910 回答
5
  • 将所有Icons 放入某种形式的数组中

  • 创建一个Timer短延迟的 Swing

  • 在 SwingActionListener中,从数组中获取每个 `Icon,从屏幕中获取边界,将 Icon 移动一步

  • 重复直到达到目标。

于 2012-05-30T04:23:30.617 回答