我正在用Java制作2D游戏,玩家可以通过障碍物引导多边形。多边形上下移动,游戏世界向左和向右滚动。我需要多边形绕其中心旋转,但是由于它不断地被平移,所以它绕着点旋转。尝试将其平移回原始中心,旋转并重新平移不起作用。如何获得形状的中心?
这是我在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(); } }
这是我的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); } }
其中(xPos,yPos)是屏幕的中心。
转换(通常)是复杂的
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); } }
在以上代码中,您正在翻译原始Graphics上下文和copy。在这种情况下,原始上下文copy不会受到的影响copy,但原始上下文是共享资源,并且由于您不重置翻译,因此您将继续获取翻译后的上下文每次(复合)。
Graphics
copy
作为一般经验法则,对副本执行所有转换,并在完成后将其处理。
例如…
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();
基本上,这会将对象的位置转换为玩家的位置,然后围绕对象的中心旋转对象
您还可以应用一个转换,创建该上下文的副本,然后应用另一个转换,该转换将变得复杂(因此,您可以将translate一个上下文复制,然后rotate将副本和第一个译文应用于副本)
translate
rotate
这个令人难以置信的简单示例演示了两个基本示例…
AffineTransform
Path2D
在两种情况下,它们都不会影响原始形状
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(); } } }