如何在 java 中围绕另一个移动物体旋转一个物体?
How to rotate an object around another moving object in java?
我对 Java 很陌生,想编写一个简单的太阳系,其中月球绕地球旋转,地球绕太阳旋转。
一切都很好,除了月亮不想正确移动:/
由于地球偏离月球的初始位置,月球的自转半径相应地增加到那个距离。再次当地球靠近月球惯性位置时,自转半径减小。
如果初始位置是(0;0),它有效但是月亮撞到太阳...
那么我怎样才能保持地球和月球之间的距离不变呢?
我正在使用 AffineTransforms,这是我的代码片段 ;)
提前致谢!
Ellipse2D.Double MoonFrame = new Ellipse2D.Double(orbitEarth + orbitMoon - radiusMoon, -radiusMoon, radiusMoon*2, radiusMoon*2);
for (int i = 0; i < 360; i++)
{
theta += Math.PI/30;
AffineTransform TransformMoon = AffineTransform.getRotateInstance(theta,TransformEarth.getTranslateX(),TransformEarth.getTranslateY());
g2d.fill(TransformMond.createTransformedShape(MoonFrame));
}
所以,您的基本问题归结为 "how do I find a point on a circle for a give angle" ...说真的,就这么简单
基于许多小时的谷歌搜索和反复试验,我基本上或多或少地使用以下内容。
protected Point pointOnCircle() {
double rads = Math.toRadians(orbitAngle - 180); // Make 0 point out to the right...
int fullLength = Math.round((outterRadius));
// Calculate the outter point of the line
int xPosy = Math.round((float) (Math.cos(rads) * fullLength));
int yPosy = Math.round((float) (Math.sin(rads) * fullLength));
return new Point(xPosy, yPosy);
}
剩下的基本上归结为正确处理转换的复合性质,
基本上,这需要一个基础 Graphics
上下文,对其应用转换(地球的位置)并创建另外两个上下文以应用额外的转换,一个用于地球,一个用于月球。 ..
Graphics2D g2d = (Graphics2D) g.create();
int yPos = (getHeight() - size) / 2;
// Transform the offset
g2d.transform(AffineTransform.getTranslateInstance(xPos, yPos));
Graphics2D earthG = (Graphics2D) g2d.create();
// Rotate around the 0x0 point, this becomes the center point
earthG.transform(AffineTransform.getRotateInstance(Math.toRadians(angle)));
// Draw the "earth" around the center point
earthG.drawRect(-(size / 2), -(size / 2), size, size);
earthG.dispose();
// Removes the last transformation
Graphics2D moonG = (Graphics2D) g2d.create();
// Calclate the point on the circle - based on the outterRadius or
// distance from the center point of the earth
Point poc = pointOnCircle();
int moonSize = size / 2;
// This is only a visial guide used to show the position of the earth
//moonG.drawOval(-outterRadius, -outterRadius, outterRadius * 2, outterRadius * 2);
moonG.fillOval(poc.x - (moonSize / 2), poc.y - (moonSize / 2), moonSize, moonSize);
moonG.dispose();
g2d.dispose();
而且因为我知道这会让你挠头,一个可运行的例子...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private double angle;
private double orbitAngle;
private int xPos = 0;
private int size = 20;
private int outterRadius = size * 2;
private int delta = 2;
public TestPane() {
new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
xPos += delta;
if (xPos + size >= getWidth()) {
xPos = getWidth() - size;
delta *= -1;
} else if (xPos < 0) {
xPos = 0;
delta *= -1;
}
angle += 4;
orbitAngle -= 2;
repaint();
}
}).start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
protected Point pointOnCircle() {
double rads = Math.toRadians(orbitAngle - 180); // Make 0 point out to the right...
int fullLength = Math.round((outterRadius));
// Calculate the outter point of the line
int xPosy = Math.round((float) (Math.cos(rads) * fullLength));
int yPosy = Math.round((float) (Math.sin(rads) * fullLength));
return new Point(xPosy, yPosy);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int yPos = (getHeight() - size) / 2;
// Transform the offset
g2d.transform(AffineTransform.getTranslateInstance(xPos, yPos));
Graphics2D earthG = (Graphics2D) g2d.create();
// Rotate around the 0x0 point, this becomes the center point
earthG.transform(AffineTransform.getRotateInstance(Math.toRadians(angle)));
// Draw the "earth" around the center point
earthG.drawRect(-(size / 2), -(size / 2), size, size);
earthG.dispose();
// Removes the last transformation
Graphics2D moonG = (Graphics2D) g2d.create();
// Calclate the point on the circle - based on the outterRadius or
// distance from the center point of the earth
Point poc = pointOnCircle();
int moonSize = size / 2;
// This is only a visial guide used to show the position of the earth
//moonG.drawOval(-outterRadius, -outterRadius, outterRadius * 2, outterRadius * 2);
moonG.fillOval(poc.x - (moonSize / 2), poc.y - (moonSize / 2), moonSize, moonSize);
moonG.dispose();
g2d.dispose();
}
}
}
这会移动一个 "Earth" 物体,该物体沿一个方向旋转,然后绕着它旋转月亮,沿相反方向旋转
您可以通过串联转换来简化数学运算。从最后一个转换倒退到第一个,或使用 preConcatenate
以更自然的顺序构建它们。
从简单的变换组成复杂的变换,例如通过平移和旋转构建轨道变换:
// Earth transform.
// Set the orbital radius to 1/3rd the panel width
AffineTransform earthTx = AffineTransform.getTranslateInstance(getWidth() / 3, 0);
// Rotate
earthTx.preConcatenate(AffineTransform.getRotateInstance(angle));
之后的变换(例如,月球绕地球运行)可以建立在之前的结果之上:
// Moon transform.
// Set the orbital radius to 1/10th the panel width
AffineTransform moonTx = AffineTransform.getTranslateInstance(getWidth() / 10, 0);
// Rotate
moonTx.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the earth transform
moonTx.preConcatenate(earthTx);
完整示例:
public class Orbit {
public static class OrbitPanel extends JComponent {
int width;
int height;
public OrbitPanel(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Clear the background.
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
// Sun transform. Just centre it in the window.
AffineTransform sunTx = AffineTransform.getTranslateInstance(getWidth() / 2, getHeight() / 2);
// Draw the sun
g2.setTransform(sunTx);
drawBody(g2, 30, Color.YELLOW);
// Orbital period.
// One rotation every 10s.
double percentRotation = System.currentTimeMillis() % 10000 / 10000.0;
// To radians.
double angle = Math.PI * 2 * percentRotation;
// Earth transform.
// Set the orbital radius to 1/3rd the panel width
AffineTransform earthTx = AffineTransform.getTranslateInstance(getWidth() / 3, 0);
// Rotate
earthTx.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the sun transform
earthTx.preConcatenate(sunTx);
// Draw the earth
g2.setTransform(earthTx);
drawBody(g2, 10, Color.BLUE);
// Moon transform.
// Set the orbital radius to 1/10th the panel width
AffineTransform moonTx = AffineTransform.getTranslateInstance(getWidth() / 10, 0);
// Rotate
moonTx.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the earth transform (already includes the sun transform)
moonTx.preConcatenate(earthTx);
// Draw the moon
g2.setTransform(moonTx);
drawBody(g2, 5, Color.DARK_GRAY);
}
private void drawBody(Graphics2D g2, int size, Color color) {
g2.setColor(color);
g2.fillOval(-size / 2, -size / 2, size, size);
}
}
public static void main(String[] args) throws IOException, InterruptedException {
JFrame frame = new JFrame("Orbit");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JComponent orbitPanel = new OrbitPanel(250, 250);
frame.add(orbitPanel);
frame.pack();
frame.setVisible(true);
while (true) {
Thread.sleep(20);
orbitPanel.repaint();
}
}
}
我对 Java 很陌生,想编写一个简单的太阳系,其中月球绕地球旋转,地球绕太阳旋转。 一切都很好,除了月亮不想正确移动:/ 由于地球偏离月球的初始位置,月球的自转半径相应地增加到那个距离。再次当地球靠近月球惯性位置时,自转半径减小。 如果初始位置是(0;0),它有效但是月亮撞到太阳...
那么我怎样才能保持地球和月球之间的距离不变呢? 我正在使用 AffineTransforms,这是我的代码片段 ;)
提前致谢!
Ellipse2D.Double MoonFrame = new Ellipse2D.Double(orbitEarth + orbitMoon - radiusMoon, -radiusMoon, radiusMoon*2, radiusMoon*2);
for (int i = 0; i < 360; i++)
{
theta += Math.PI/30;
AffineTransform TransformMoon = AffineTransform.getRotateInstance(theta,TransformEarth.getTranslateX(),TransformEarth.getTranslateY());
g2d.fill(TransformMond.createTransformedShape(MoonFrame));
}
所以,您的基本问题归结为 "how do I find a point on a circle for a give angle" ...说真的,就这么简单
基于许多小时的谷歌搜索和反复试验,我基本上或多或少地使用以下内容。
protected Point pointOnCircle() {
double rads = Math.toRadians(orbitAngle - 180); // Make 0 point out to the right...
int fullLength = Math.round((outterRadius));
// Calculate the outter point of the line
int xPosy = Math.round((float) (Math.cos(rads) * fullLength));
int yPosy = Math.round((float) (Math.sin(rads) * fullLength));
return new Point(xPosy, yPosy);
}
剩下的基本上归结为正确处理转换的复合性质,
基本上,这需要一个基础 Graphics
上下文,对其应用转换(地球的位置)并创建另外两个上下文以应用额外的转换,一个用于地球,一个用于月球。 ..
Graphics2D g2d = (Graphics2D) g.create();
int yPos = (getHeight() - size) / 2;
// Transform the offset
g2d.transform(AffineTransform.getTranslateInstance(xPos, yPos));
Graphics2D earthG = (Graphics2D) g2d.create();
// Rotate around the 0x0 point, this becomes the center point
earthG.transform(AffineTransform.getRotateInstance(Math.toRadians(angle)));
// Draw the "earth" around the center point
earthG.drawRect(-(size / 2), -(size / 2), size, size);
earthG.dispose();
// Removes the last transformation
Graphics2D moonG = (Graphics2D) g2d.create();
// Calclate the point on the circle - based on the outterRadius or
// distance from the center point of the earth
Point poc = pointOnCircle();
int moonSize = size / 2;
// This is only a visial guide used to show the position of the earth
//moonG.drawOval(-outterRadius, -outterRadius, outterRadius * 2, outterRadius * 2);
moonG.fillOval(poc.x - (moonSize / 2), poc.y - (moonSize / 2), moonSize, moonSize);
moonG.dispose();
g2d.dispose();
而且因为我知道这会让你挠头,一个可运行的例子...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private double angle;
private double orbitAngle;
private int xPos = 0;
private int size = 20;
private int outterRadius = size * 2;
private int delta = 2;
public TestPane() {
new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
xPos += delta;
if (xPos + size >= getWidth()) {
xPos = getWidth() - size;
delta *= -1;
} else if (xPos < 0) {
xPos = 0;
delta *= -1;
}
angle += 4;
orbitAngle -= 2;
repaint();
}
}).start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
protected Point pointOnCircle() {
double rads = Math.toRadians(orbitAngle - 180); // Make 0 point out to the right...
int fullLength = Math.round((outterRadius));
// Calculate the outter point of the line
int xPosy = Math.round((float) (Math.cos(rads) * fullLength));
int yPosy = Math.round((float) (Math.sin(rads) * fullLength));
return new Point(xPosy, yPosy);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int yPos = (getHeight() - size) / 2;
// Transform the offset
g2d.transform(AffineTransform.getTranslateInstance(xPos, yPos));
Graphics2D earthG = (Graphics2D) g2d.create();
// Rotate around the 0x0 point, this becomes the center point
earthG.transform(AffineTransform.getRotateInstance(Math.toRadians(angle)));
// Draw the "earth" around the center point
earthG.drawRect(-(size / 2), -(size / 2), size, size);
earthG.dispose();
// Removes the last transformation
Graphics2D moonG = (Graphics2D) g2d.create();
// Calclate the point on the circle - based on the outterRadius or
// distance from the center point of the earth
Point poc = pointOnCircle();
int moonSize = size / 2;
// This is only a visial guide used to show the position of the earth
//moonG.drawOval(-outterRadius, -outterRadius, outterRadius * 2, outterRadius * 2);
moonG.fillOval(poc.x - (moonSize / 2), poc.y - (moonSize / 2), moonSize, moonSize);
moonG.dispose();
g2d.dispose();
}
}
}
这会移动一个 "Earth" 物体,该物体沿一个方向旋转,然后绕着它旋转月亮,沿相反方向旋转
您可以通过串联转换来简化数学运算。从最后一个转换倒退到第一个,或使用 preConcatenate
以更自然的顺序构建它们。
从简单的变换组成复杂的变换,例如通过平移和旋转构建轨道变换:
// Earth transform.
// Set the orbital radius to 1/3rd the panel width
AffineTransform earthTx = AffineTransform.getTranslateInstance(getWidth() / 3, 0);
// Rotate
earthTx.preConcatenate(AffineTransform.getRotateInstance(angle));
之后的变换(例如,月球绕地球运行)可以建立在之前的结果之上:
// Moon transform.
// Set the orbital radius to 1/10th the panel width
AffineTransform moonTx = AffineTransform.getTranslateInstance(getWidth() / 10, 0);
// Rotate
moonTx.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the earth transform
moonTx.preConcatenate(earthTx);
完整示例:
public class Orbit {
public static class OrbitPanel extends JComponent {
int width;
int height;
public OrbitPanel(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Clear the background.
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
// Sun transform. Just centre it in the window.
AffineTransform sunTx = AffineTransform.getTranslateInstance(getWidth() / 2, getHeight() / 2);
// Draw the sun
g2.setTransform(sunTx);
drawBody(g2, 30, Color.YELLOW);
// Orbital period.
// One rotation every 10s.
double percentRotation = System.currentTimeMillis() % 10000 / 10000.0;
// To radians.
double angle = Math.PI * 2 * percentRotation;
// Earth transform.
// Set the orbital radius to 1/3rd the panel width
AffineTransform earthTx = AffineTransform.getTranslateInstance(getWidth() / 3, 0);
// Rotate
earthTx.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the sun transform
earthTx.preConcatenate(sunTx);
// Draw the earth
g2.setTransform(earthTx);
drawBody(g2, 10, Color.BLUE);
// Moon transform.
// Set the orbital radius to 1/10th the panel width
AffineTransform moonTx = AffineTransform.getTranslateInstance(getWidth() / 10, 0);
// Rotate
moonTx.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the earth transform (already includes the sun transform)
moonTx.preConcatenate(earthTx);
// Draw the moon
g2.setTransform(moonTx);
drawBody(g2, 5, Color.DARK_GRAY);
}
private void drawBody(Graphics2D g2, int size, Color color) {
g2.setColor(color);
g2.fillOval(-size / 2, -size / 2, size, size);
}
}
public static void main(String[] args) throws IOException, InterruptedException {
JFrame frame = new JFrame("Orbit");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JComponent orbitPanel = new OrbitPanel(250, 250);
frame.add(orbitPanel);
frame.pack();
frame.setVisible(true);
while (true) {
Thread.sleep(20);
orbitPanel.repaint();
}
}
}