2

画像付きのラベルを円形パスで移動する必要があるシミュレーションのようなスプライトを書いています。出発点は 4 つあります。西、北、東、南。ラベルは時計回りに移動する必要があります。

これは私が書いたもので、北と南の位置が反時計回りに回転するという事実を除いて、うまく機能します。その理由は、方向 2 と 4 を処理するために別の三角関数を使用したからです。

    int xstart = 450 
    int ystart = 325;
    int h = 0;
    double theta = -0.1047;

    for (int p = 0;; p++)
    {
        int xocir = xstart;
        int yocir = ystart;
        int pocir = 0; // perpendicular and base of outer circle
        int bocir = 0;

        if (direction == 1)//west - clockwise
        {
            pocir = (int) (Math.cos(theta) * (h + 300));
            bocir = (int) (Math.sin(theta) * (h + 300));
        }
        else if (direction == 2)//north - counter-clockwise
        {
            pocir = (int) (Math.sin(theta) * (h + 300));//reversed sin,cos
            bocir = (int) (Math.cos(theta) * (h + 300));
        }
        else if (direction == 3)//east - clockwise
        {
            pocir = (int) (Math.cos(theta) * (h - 300));
            bocir = (int) (Math.sin(theta) * (h - 300));
        }
        else if (direction == 4)//south - counter-clockwise
        {
            pocir = (int) (Math.sin(theta) * (h - 300));
            bocir = (int) (Math.cos(theta) * (h - 300));
        }

        xocir = xocir - pocir;
        yocir = yocir - bocir;
        theta = theta - 0.005;

        setBounds(xocir, yocir, 65, 65);
            }

これに取り組むより効率的な方法はありますか?たぶん、より単純なトリガー方法です。そして、すべての動きが時計回りであることを確認するにはどうすればよいですか?

4

2 に答える 2

4

方向に応じて異なる方程式の代わりに、時計回りのifステートメントの1つを使用してください。開始位置は、シータの初期値と使用されるパラメトリック方程式によって制御されます。

x = 、
y = 、= 450、= 325、および=300とします。circleCenterX - (int) (Math.sin(theta) * radius)
circleCenterY - (int) (Math.cos(theta) * radius)
circleCenterX
circleCenterY
radius

If theta = 0 deg, then
(x,y) = (450 - sin(0) * 300, 325 - cos(0) * 300)
      = (450, 25) which is north of (450, 325)

If theta = 90 deg, then
(x,y) = (450 - sin(90) * 300, 325 - cos(90) * 300)
      = (150, 325) which is west of (450, 325)

If theta = 180 deg, then
(x,y) = (450 - sin(180) * 300, 325 - cos(180) * 300)
      = (450, 625) which is south of (450, 325)

If theta = 270 deg, then
(x,y) = (450 - sin(270) * 300, 325 - cos(270) * 300)
      = (750, 325) which is east of (450, 325)

次のクラスは、このアイデアをカプセル化します。

import java.awt.Dimension;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class RotatingLabel extends JLabel {
    private static final long serialVersionUID = 474652899660954020L;
    private final int circleCenterX;
    private final int circleCenterY;
    private final int radius;
    private double theta;
    private final double thetaIncrement;

    public RotatingLabel(String text, //
            int circleCenterX, int circleCenterY, int radius, //
            double initialTheta, double thetaIncrement) {
        super(text);
        this.circleCenterX = circleCenterX;
        this.circleCenterY = circleCenterY;
        this.radius = radius;
        this.theta = initialTheta;
        this.thetaIncrement = thetaIncrement;
        rotate();
    }

    public void rotate() {
        setBounds( //
                this.circleCenterX - (int) (Math.sin(this.theta) * this.radius), //
                this.circleCenterY - (int) (Math.cos(this.theta) * this.radius), //
                (int) getPreferredSize().getWidth(), (int) getPreferredSize().getHeight());
        this.theta -= this.thetaIncrement;
    }

    public static void main(String[] args) {
        double initialTheta = Math.toRadians(0); // start north
        // double initialTheta = Math.toRadians(90); // start west
        // double initialTheta = Math.toRadians(180); // start south
        // double initialTheta = Math.toRadians(270); // start east

        final RotatingLabel label = new RotatingLabel("Foo Bar", //
                450, // circleCenterX
                325, // circleCenterY
                300, // radius
                initialTheta, //
                0.005); // thetaIncrement

        JFrame frame = new JFrame();
        frame.setSize(new Dimension(800, 700));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(label);
        frame.setVisible(true);

        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        label.rotate();
                    }
                });
            }
        }, 0, 1000l / 60l); // 60 frames per second
    }
}
于 2012-06-03T20:04:43.117 に答える
3

繰り返しますが、すべての象限に対して 1 つの方程式を使用してください。たとえば、このコードは 4 つの JLabel を示し、各象限に 1 つずつあり (それぞれが隣接するものから Math.PI/2 を回転させます)、同じ方程式を使用してすべてのラベルを回転させます。

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class RotateLabels extends JPanel{
   private static final int PREF_W = 600;
   private static final int PREF_H = PREF_W;
   private static final int TIMER_DELAY = 30;
   protected static final double DELTA_THETA = Math.PI / 120;
   private JLabel[] labels = new JLabel[4];
   private double theta = -Math.PI / 4.0;

   public RotateLabels() {
      setLayout(null);
      for (int i = 0; i < labels.length; i++) {
         labels[i] = new JLabel("Label " + (i + 1));
         labels[i].setSize(labels[i].getPreferredSize());
         add(labels[i]);
      }
      setAllLabelLocations();
      new Timer(TIMER_DELAY, new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            theta += DELTA_THETA;
            setAllLabelLocations();
         }
      }).start();
   }

   private void setAllLabelLocations() {
      for (int i = 0; i < labels.length; i++) {
         setLabelLocation(labels[i], i);
      }
      repaint();
   }

   private void setLabelLocation(JLabel label, int i) {
      double radius = PREF_W / 3.0;
      int w = label.getWidth();
      int h = label.getHeight();

      double angle = theta + i * Math.PI / 2.0;
      double centerX = radius * Math.cos(angle);
      double centerY = radius * Math.sin(angle);

      int x = (int)(centerX - w / 2.0) + PREF_W / 2;
      int y = (int)(centerY - h / 2.0) + PREF_H / 2;
      label.setLocation(x, y);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("Rotate");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new RotateLabels());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

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

このコードはあまり効率的ではないことに注意してください。これを「実際に」作成する場合、プログラムの実行中に発生するすべての浮動小数点計算を回避するために、おそらく位置ルックアップ テーブルを作成するでしょう。

またはより一般的に:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class RotateLabels2 extends JPanel{
   private static final int PREF_W = 600;
   private static final int PREF_H = PREF_W;
   private static final int TIMER_DELAY = 10;
   protected static final double DELTA_THETA = Math.PI / 420;
   private static final int LABEL_COUNT = 12;
   private JLabel[] labels = new JLabel[LABEL_COUNT];
   private double theta = -Math.PI / 4.0;

   public RotateLabels2() {
      setLayout(null);
      for (int i = 0; i < labels.length; i++) {
         labels[i] = new JLabel("Label " + (i + 1));
         labels[i].setSize(labels[i].getPreferredSize());
         add(labels[i]);
      }
      setAllLabelLocations();
      new Timer(TIMER_DELAY, new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            theta += DELTA_THETA;
            setAllLabelLocations();
         }
      }).start();
   }

   private void setAllLabelLocations() {
      for (int i = 0; i < labels.length; i++) {
         setLabelLocation(labels[i], i);
      }
      repaint();
   }

   private void setLabelLocation(JLabel label, int i) {
      double radius = PREF_W / 3.0;
      int w = label.getWidth();
      int h = label.getHeight();

      double angle = theta + i * 2 * Math.PI / labels.length;
      double centerX = radius * Math.cos(angle);
      double centerY = radius * Math.sin(angle);

      int x = (int)(centerX - w / 2.0) + PREF_W / 2;
      int y = (int)(centerY - h / 2.0) + PREF_H / 2;
      label.setLocation(x, y);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("Rotate");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new RotateLabels2());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
于 2012-06-03T20:37:05.460 に答える