我正在写一个类似于模拟的精灵,我需要在圆形路径中移动带有图像的标签。我有4个起点;西,北,东,南。标签应以顺时针方式移动。
这是我写的,它运作良好,除了北和南位置逆时针旋转的事实。原因是,我使用了一个单独的trig公式来处理方向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);
}
有没有更有效的方法来解决这个问题?也许是一种更简单的trig方法。我该怎么做才能确保所有动作都是顺时针的?
答案 0 :(得分:4)
根据方向,只使用顺时针if语句中的一个而不是不同的等式。起始位置由theta的初始值和使用的参数方程控制。
让
x = circleCenterX - (int) (Math.sin(theta) * radius)
,
y = circleCenterY - (int) (Math.cos(theta) * radius)
,
circleCenterX
= 450,
circleCenterY
= 325,和
radius
= 300。
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
}
}
答案 1 :(得分:3)
同样,只需对所有象限使用一个等式。例如,此代码显示4个JLabel,每个象限中一个(每个象限从其邻居旋转Math.PI / 2),并使用相同的等式旋转 all 标签:
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();
}
});
}
}
请注意,此代码效率不高。如果我要创建“for real”,我可能会创建一个位置查找表,以避免在程序运行期间发生的所有浮点计算。
或更一般地说:
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();
}
});
}
}