围绕其中心旋转移动的形状

时间:2017-12-04 05:40:30

标签: java rotation graphics2d affinetransform

我在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)是屏幕的中心。

2 个答案:

答案 0 :(得分:1)

转换(通常)复合

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的影响,但原始上下文是共享资源,因为您不重置翻译,每次你都会继续得到一个翻译的上下文(复合)。

作为一般经验法则,请在完成后对副本进行所有转换并在完成后将其丢弃。

例如......

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复制和第一次翻译仍然适用于副本)

这个令人难以置信的简单例子展示了两个基本的例子......

  1. 使用Graphics上下文和AffineTransform翻译和旋转玩家对象(关于它的中心点)
  2. 使用Path2D生成转换后的形状(此示例生成两个对象,但您可以使用单个AffineTransform进行翻译并旋转并应用一次。)
  3. 在这两种情况下,它们都不会影响原始形状

    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();
            }
    
        }
    }
    

答案 1 :(得分:0)

在openGL中,我们使用pushMatrix()popMatrix()保存转换状态。这里的等价物是Graphics.create()Graphics.dispose()

Graphics g1 = g.create();
//do transformations
g1.dispose();

Graphics g2 = g.create();
//do other stuff
g2.dispose();