简体   繁体   English

Java-将图像旋转到位

[英]Java - rotate image in place

I have a tank cannon layer that should rotate toward the mouse position, which I have done with the following code: 我有一个坦克大炮层,它应该朝着鼠标的位置旋转,这是通过以下代码完成的:

double theta = Math.atan2(point.getY() - center.getY(), point.getX() - center.getX());

then I rotate the graphics object's transform accordingly. 然后我相应地旋转图形对象的变换。 This works, but the cannon rotates around the cannon's center. 这可行,但是大炮围绕大炮的中心旋转。 I want the cannon's base to stay in position when the rotation happens. 我希望大炮的底部在旋转发生时保持在原位。 I've tried many different positions to rotate around, but I can't get one that will keep its base in position. 我已经尝试过许多不同的位置来旋转,但是我找不到一个可以将其底座保持在适当位置的位置。 I think that I must translate the graphics object after rotation to where the cannon's base should be, but I don't know how. 我认为旋转后必须将图形对象平移到加农炮的底部,但我不知道如何。 My cannon with both layers: 我的两层大炮: 在此处输入图片说明

As you can see, the base (the light green part) must stay in it's position. 如您所见,底座(浅绿色部分)必须保持在原位。 How can I achieve this? 我该如何实现?

Okay, assuming that the turret and base are separate images, and the turret isn't the same size as the tank (cause then it becomes complicated....more then it actually is :P) 好吧,假设炮塔和炮塔是分开的图像,并且炮塔的大小与坦克的大小不同(因为这会使其变得复杂...更多,实际上它是:P)

You can use a AffineTransform and compound the transformations... 您可以使用AffineTransform并复合转换...

    // This is the x/y position of the top, at the top/left point,
    // I've placed it at the center of my screen, but you get the idea
    double x = (getWidth() - base.getWidth()) / 2d;
    double y = (getHeight() - base.getHeight()) / 2d;

    // Translate the location to the x/y, this makes the top/left 0x0...
    // much easier to deal with...
    AffineTransform at = AffineTransform.getTranslateInstance(x, y);
    g2d.setTransform(at);
    // Draw the base...
    g2d.drawImage(base, 0, 0, this);

    // Offset the turret, in my testing, this was 8x8 from the bases
    // top/left
    at.translate(8, 8);
    if (targetPoint != null) {
        // Calculate the delta between the mouse and the center point
        // of the turret, this is in screen coordinates and not
        // translated coordinates
        double deltaX = (x + 8) - targetPoint.x;
        double deltaY = (y + 8) - targetPoint.y;

        // Calculate the rotation required to point at the mouse
        // Had to apply an offset to allow for the default orientation
        // of the tank...
        double rotation = Math.atan2(deltaY, deltaX) + Math.toRadians(180d);
        // Rotate around the anchor point of the turret
        // Remember, we've translated so the top/left (0x0) is now the
        // turrets default position
        at.rotate(rotation, 4, 4);
    }
    // Transform the Graphics context
    g2d.setTransform(at);
    // Paint the turret
    g2d.drawImage(turret, 0, 0, this);
}
g2d.dispose();

And because I went to effort... 而且因为我努力...

My assets... 我的资产

基础炮塔

罐

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.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class FollowMe {

    public static void main(String[] args) {
        new FollowMe();
    }

    public FollowMe() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Point targetPoint;
        private BufferedImage turret;
        private BufferedImage base;

        public TestPane() {
            addMouseMotionListener(new MouseAdapter() {

                @Override
                public void mouseMoved(MouseEvent e) {
                    targetPoint = e.getPoint();
                    repaint();
                }

            });
            try {
                base = ImageIO.read(getClass().getResource("/Base.png"));
                turret = ImageIO.read(getClass().getResource("/Turret.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
            g.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
            if (base != null) {
                double x = (getWidth() - base.getWidth()) / 2d;
                double y = (getHeight() - base.getHeight()) / 2d;
                // Test line from center of tank to mouse poisition
                if (targetPoint != null) {
                    g2d.draw(new Line2D.Double((x + 12), (y + 12), targetPoint.x, targetPoint.y));
                }
                AffineTransform at = AffineTransform.getTranslateInstance(x, y);
                g2d.setTransform(at);
                g2d.drawImage(base, 0, 0, this);
                at.translate(8, 8);
                if (targetPoint != null) {
                    double deltaX = (x + 8) - targetPoint.x;
                    double deltaY = (y + 8) - targetPoint.y;

                    double rotation = Math.atan2(deltaY, deltaX) + Math.toRadians(180d);
                    at.rotate(rotation, 4, 4);
                }
                g2d.setTransform(at);
                g2d.drawImage(turret, 0, 0, this);
            }
            g2d.dispose();
        }

    }

}

Have a look at Transforming Shapes, Text, and Images for more details 有关更多信息,请参见变换形状,文本和图像

Your formula just shows how you calculate the angle - your question seems to be 'how to rotate an image around a specified point'. 您的公式仅显示了如何计算角度-您的问题似乎是“如何围绕指定点旋转图像”。 For that i would recommend using AffineTransform s (matrices math). 为此,我建议使用AffineTransform (矩阵数学)。 A good point to start is here: http://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html . 一个很好的起点是: http : //docs.oracle.com/javase/tutorial/2d/advanced/transforming.html

Some sample code: 一些示例代码:

Graphics2D g; //<- you should have this in your code somewhere
AffineTransform at = new AffineTransform(); 
at.rotate(theta, centerX, centerY); //<- your question: rotate around specified point
g.setTransform(at); //<- tell the graphics to transform before painting
g.drawImage(...); //<- draws transformed image

If you look deeper into AffineTransform.rotate(...) you see that at first a translation is made, then the rotation. 如果深入研究AffineTransform.rotate(...)您会发现首先进行转换,然后进行旋转。 The third transform is a translation with the negative x/y values. 第三个变换是x / y值为负的转换。

This is the good old code from sun: 这是来自sun的很好的旧代码:

public void rotate(double theta, double anchorx, double anchory) {
    // REMIND: Simple for now - optimize later
    translate(anchorx, anchory);
    rotate(theta);
    translate(-anchorx, -anchory);
}

Working with matrices is pretty powerful as you can combine translations, rotations, shear, mirror and whatnot. 使用矩阵非常强大,因为您可以结合平移,旋转,剪切,镜像和其他功能。 Not only in 2d but also in 3d. 不仅在2d中,而且在3d中。 Maybe your tank will someday leave the flat world and become a volume model... 也许您的坦克有一天会离开平坦的世界,成为一个体积模型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM