3

私は(あるべきである)取り組むべき単純な問題を抱えており、それを解決する他の方法を受け入れています。私は他の解決策を受け入れています。

問題:Javaスイングを使用して、ターンベースのタイルベースのゲームのグラフィックを表示しています。絶対に配置されたアイコン付きのjlabelを使用しています。

動きをアニメートするために、一度に4ピクセルずつ位置を更新するスイングタイマーを使用して、スプライトをゆっくりと右、左などに動かしています。

これを最初に達成するために、私はタイマーを実行していました。これは素晴らしい働きをします。下に移動してから右に移動しようとすると、問題が発生します。

スプライトは下に移動し、右に移動することはありません。コンソール印刷で実行を見ると、両方のタイマーが同時に実行されていることがわかります。私はインターネットでかなりの量の掘り下げを行いましたが、最初のタイマーが停止するまでスイングタイマーを実行しないように指示する方法を見つけることができませんでした。ビジーウェイトをしようとすると、1つのタイマーが終了するまで待ちます(うん)UIがまったく表示されない(明らかに間違った方向へのステップ)。

これで、タイマーから完全に離れて、スプライトを新しい場所にテレポートするか、ひどいビジーウェイト移動スキームを使用することができますが、ある種の魂が解決策を持っていることを望んでいます。

つまり、スイングタイマーを一定時間実行し、停止してから、新しいタイマー開始して、オーバーラップしないようにする方法が必要です。できれば、このメソッドを使用すると、各タイマーを独自のメソッドに含めることができ、メソッドを次々に呼び出すことができます。

あなたが持っているかもしれないどんなアドバイスにも前もって感謝します。

編集:拡張されたサンプルコード。完全なscsseがアドバイスの要件である場合、完全なコードは獣であるため、時間を無駄にして申し訳ありません。このサンプルコードは、現状ではまったく機能しません。申し訳ありませんが、要点を説明する必要があります。

それで。2つの機能があり、それぞれにアニメーションサイクルを実行するタイマーがあり、1つは下と右斜めに移動するためのもので、もう1つは真下に移動するためのものです。

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*

ここで取得しようとしているポイントは、1つのアニメーションサイクルを実行して完了し、次にもう1つのアニメーションサイクルを実行することです。

再度、感謝します。

4

3 に答える 3

6

複数のタイマーを使用しないでください。必要に応じて各方向を処理するタイマーを 1 つだけ使用してください。方向情報を保持するには、何らかのタイプのキュー (正式なキューまたはキューとして使用するコレクション (先入れ先出し) のいずれか) が必要です。次に、タイマーが実行中にこのキューから方向を抽出します。たとえば、ここでは、最初に (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

参考までに、このでは の 4 つのインスタンスを管理していますTimer。そのうちの 2 つは、任意の隅にホバリングしているときに (インターリーブされて) 実行されます。それをあなたのアプローチと比較するかもしれません。この関連する回答では、同様のタイルベースのゲームでのアニメーションについて説明しています。

于 2012-05-30T04:18:40.910 に答える
5
  • Iconすべての s を何らかの形式の配列に入れる

  • Timer短い遅延で単一のスイングを作成する

  • SwingActionListenerでは、配列から各 `Icon を取得し、画面から getBounds を取得し、Icon を 1 ステップ移動します

  • 目標に到達するまで繰り返します。

于 2012-05-30T04:23:30.617 に答える