[英]Rotate a moving shape around its center
I'm making a 2D game in Java where the player guides a polygon through obstacles. 我正在用Java制作2D游戏,玩家可以通过障碍物引导多边形。 The polygon moves up and down and the game world scrolls left and right.
多边形上下移动,游戏世界向左和向右滚动。 I need the polygon to rotate around its center, but since it is constantly being translated the point it is being rotated around moves.
我需要多边形绕其中心旋转,但是由于它不断地被平移,所以它绕着点旋转。 Trying to translate it back to the original center, rotate it, and translate it back doesn't work.
尝试将其平移回原始中心,然后旋转,然后再平移回原处。 How do I get the center of the shape?
如何获得形状的中心?
Here are my motion calculations on a 2ms timer: 这是我在2ms计时器上的运动计算:
@Override
public void actionPerformed(ActionEvent e) {
double theta = angleRad+90;
if (up == true) {
if (accelerating == false) {
time2 = 0;
moveX0 = moveX;
moveY0 = moveY;
accelerating = true;
}
time1++;
double t = time1/500;
if (accCount % 10 == 0) {
DronePilot.velocity++;
}
moveX = moveX0 + velX*Math.cos(theta)*t;
moveY = moveY0 + velY*Math.sin(theta)*t-(1/2d)*g*Math.pow(t, 2);
velX = (DronePilot.velocity)*Math.cos(theta);
velY = (DronePilot.velocity)*Math.sin(theta)-g*(t);
accCount++;
} else if (up == false){
if (accelerating == true) {
time1 = 0;
moveX0 = moveX;
moveY0 = moveY;
accelerating = false;
}
time2++;
double t = time2/500;
moveX = moveX0 + velX*Math.cos(theta)*t;
moveY = moveY0 + velY*Math.sin(theta)*t-(1/2d)*g*Math.pow(t, 2);
accCount = 0;
} if (left == true) {
angleCount++;
if (angleCount % 2 == 0) {
angleDeg++;
}
angleRad = Math.toRadians(angleDeg);
} else if (right == true) {
angleCount--;
if (angleCount % 2 == 0) {
angleDeg--;
}
angleRad = Math.toRadians(angleDeg);
}
repaint();
}
}
And here is my paintComponent method: 这是我的paintComponent方法:
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
Graphics g2 = g.create();
Graphics2D copy = (Graphics2D)g2;
copy.rotate(-angleRad, xPos, yPos);
copy.translate(0, -moveY);
g2D.translate(-moveX, 0);
copy.draw(player.shape);
for (Rectangle2D.Double r: DronePilot.rocksFloorArray) {
g2D.draw(r);
}
for (Rectangle2D.Double r: DronePilot.rocksCeilArray) {
g2D.draw(r);
}
for (Rectangle2D.Double r: DronePilot.roomsArray) {
g2D.draw(r);
}
}
where (xPos, yPos) are the center of the screen. 其中(xPos,yPos)是屏幕的中心。
Transformations are (normally) compounding 转换(通常)是复杂的
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
Graphics g2 = g.create();
Graphics2D copy = (Graphics2D)g2;
copy.rotate(-angleRad, xPos, yPos);
copy.translate(0, -moveY);
g2D.translate(-moveX, 0);
copy.draw(player.shape);
for (Rectangle2D.Double r: DronePilot.rocksFloorArray) {
g2D.draw(r);
}
for (Rectangle2D.Double r: DronePilot.rocksCeilArray) {
g2D.draw(r);
}
for (Rectangle2D.Double r: DronePilot.roomsArray) {
g2D.draw(r);
}
}
In your above code, you are translating both the original Graphics
context and the copy
. 在上面的代码中,您正在翻译原始
Graphics
上下文和copy
。 In this context, copy
won't be affected by the original and the original won't be affected by the copy
, BUT, the original context is a shared resource and since you don't reset the translation, you will continue to get a translated context each time (compounding). 在这种情况下,
copy
不会受到原始内容的影响,而原始内容也不会受到copy
(BUT)的影响,原始内容是共享资源,并且由于您无需重置翻译,因此您将继续获得每次翻译上下文(复合)。
As a general rule of thumb, do ALL transformations on a copy and dispose of it when you're done. 根据一般经验,对副本进行所有转换,并在完成后将其处理。
For example... 例如...
Graphics2D g2d = (Graphics2D)g.create();
AffineTransform at = AffineTransform.getTranslateInstance(playerPoint.x, playerPoint.y);
at.rotate(Math.toRadians(angle), player.getBounds2D().getCenterX(), player.getBounds2D().getCenterY());
g2d.setTransform(at);
g2d.setColor(Color.RED);
g2d.fill(player);
g2d.setColor(Color.BLACK);
g2d.draw(player);
g2d.dispose();
This basically translates the position of the object to the player's position and then rotates the object about the centre of the object 这基本上将对象的位置转换为玩家的位置,然后围绕对象的中心旋转对象
You could, also, apply one transformation, create a copy of that context and apply another transformation, which would become compounded (so you could translate
one context, copy it, and then rotate
the copy and the first translation would still applied to the copy) 您还可以应用一个转换,创建该上下文的副本,然后应用另一个转换,该转换将变得复杂(因此您可以
translate
一个上下文,将其复制,然后rotate
该副本,并且第一个翻译仍将应用于该副本)
This incredible simple example demonstrates two basic example... 这个难以置信的简单示例演示了两个基本示例...
Graphics
context and a AffineTransform
to translate and rotate the player object (about it's centre point) Graphics
上下文和AffineTransform
转换和旋转播放器对象(围绕它的中心点) Path2D
to generate a transformed shape (this example makes two objects, but you could use a single AffineTransform
translated and rotated and apply it once). Path2D
生成变形的形状(此示例制作了两个对象,但是您可以使用单个AffineTransform
平移和旋转并将其应用一次)。 In both cases, they don't affect the original shape 在两种情况下,它们都不会影响原始形状
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Shape player;
private Point playerPoint;
private float angle;
private float deltaZ = 1.0f;
private int deltaX, deltaY;
public TestPane() {
player = new Rectangle(0, 0, 20, 20);
playerPoint = new Point(80, 80);
Random rnd = new Random();
deltaX = 1;
deltaY = -1;
Timer timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
playerPoint.x += deltaX;
playerPoint.y += deltaY;
Shape rotatedPlayer = rotatedAndTranslatedPlayer();
Rectangle2D bounds = rotatedPlayer.getBounds2D();
if (bounds.getX() < 0.0) {
playerPoint.x = (int)(bounds.getX() * -1);
deltaX *= -1;
} else if (bounds.getX() + bounds.getWidth() >= getWidth()) {
playerPoint.x = getWidth() - (int)bounds.getWidth();
deltaX *= -1;
}
if (bounds.getY() < 0) {
playerPoint.y = 0;
deltaY *= -1;
} else if (bounds.getY() + bounds.getHeight() > getHeight()) {
playerPoint.y = getHeight() - (int)bounds.getHeight();
deltaY *= -1;
}
angle += deltaZ;
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected Shape rotatedAndTranslatedPlayer() {
Path2D.Double rotated = new Path2D.Double(player, AffineTransform.getRotateInstance(
Math.toRadians(angle),
player.getBounds2D().getCenterX(),
player.getBounds2D().getCenterY()));
return new Path2D.Double(rotated, AffineTransform.getTranslateInstance(playerPoint.x, playerPoint.y));
}
// Simply paints the "area" that the player takes up when it's rotated and
// translated
protected void paintAutoTranslatedShape(Graphics2D g2d) {
g2d.setColor(Color.DARK_GRAY);
g2d.fill(rotatedAndTranslatedPlayer().getBounds2D());
}
// Uses a AffineTransform to translate and rotate the player
protected void paintPlayer(Graphics2D g2d) {
AffineTransform at = AffineTransform.getTranslateInstance(playerPoint.x, playerPoint.y);
at.rotate(Math.toRadians(angle), player.getBounds2D().getCenterX(), player.getBounds2D().getCenterY());
g2d.setTransform(at);
g2d.setColor(Color.RED);
g2d.fill(player);
g2d.setColor(Color.BLACK);
g2d.draw(player);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
paintAutoTranslatedShape(g2d);
g2d.dispose();
g2d = (Graphics2D) g.create();
paintPlayer(g2d);
g2d.dispose();
}
}
}
In openGL we save transformation state using pushMatrix()
and popMatrix()
. 在openGL中,我们使用
pushMatrix()
和popMatrix()
保存转换状态。 Here their equivalents are Graphics.create()
and Graphics.dispose()
在这里,它们的等效项是
Graphics.create()
和Graphics.dispose()
Graphics g1 = g.create();
//do transformations
g1.dispose();
Graphics g2 = g.create();
//do other stuff
g2.dispose();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.