提问者:小点点

到达指定位置后如何旋转矩形?


当y位置达到指定位置时,我想旋转一个矩形。我想把矩形表现为路口上的汽车——只需右转。我更喜欢旋转并继续。

代码草案如下所示:

Graphics2D g2d = (Graphics2D) g.create();
g2d.setPaint(new Color(150, 150, 0));

//1. when rectangle achieve 500 on y dimension just rotate left/right
if(y==500) {
    _rotate = true;
    g2d.rotate(Math.toRadians(90.));
}
if(_rotate) { //if rotate, continue way on x dimension
    ++x ;
    g2d.fillRect(x, y, 20, 40);
} else { //else go to the north
    --y;
    g2d.fillRect(x, y, 20, 40);
}

共1个答案

匿名用户

你的问题遗漏了很多信息。

为了能够旋转一个形状,你需要知道一些事情,你需要知道它的当前位置和它的下一个目标位置,然后你可以简单地计算这两个点之间的角度。

那么问题就变成了,你如何计算这些位置。有很多方法可以实现这一点,下面是一个简单的路径跟踪过程。

首先,我们生成一条我们需要遵循的路径,我们使用ShapeAPI来计算路径上的点。我们使用一个简单的基于时间的动画(而不是通过点的循环,我们通过计算动画播放的时间量除以我们希望它花费的时间量来计算路径上的进度)并选择最匹配我们当前进度的点。

我们使用AffineTransform来旋转玩家形状并将生成的Shape翻译到所需的位置。放松

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PathFollow {

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

    public PathFollow() {
        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 Shape pathShape;
        private List<Point2D> points;
        private Shape car;

        private double angle;
        private Point2D pos;
        private int index;

        protected static final double PLAY_TIME = 5000; // 5 seconds...

        private Long startTime;

        public TestPane() {

            Path2D path = new Path2D.Double();
            path.moveTo(0, 200);
            path.curveTo(100, 200, 0, 100, 100, 100);
            path.curveTo(200, 100, 0, 0, 200, 0);

            pathShape = path;

            car = new Rectangle(0, 0, 10, 10);

            points = new ArrayList<>(25);
            PathIterator pi = pathShape.getPathIterator(null, 0.01);
            while (!pi.isDone()) {
                double[] coords = new double[6];
                switch (pi.currentSegment(coords)) {
                    case PathIterator.SEG_MOVETO:
                    case PathIterator.SEG_LINETO:
                        points.add(new Point2D.Double(coords[0], coords[1]));
                        break;
                }
                pi.next();
            }

//          System.out.println(points.size());
//          pos = points.get(0);
//          index = 1;
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {

                    if (startTime == null) {
                        startTime = System.currentTimeMillis();
                    }
                    long playTime = System.currentTimeMillis() - startTime;
                    double progress = playTime / PLAY_TIME;
                    if (progress >= 1.0) {
                        progress = 1d;
                        ((Timer) e.getSource()).stop();
                    }

                    int index = Math.min(Math.max(0, (int) (points.size() * progress)), points.size() - 1);

                    pos = points.get(index);
                    if (index < points.size() - 1) {
                        angle = angleTo(pos, points.get(index + 1));
                    }
                    repaint();
                }
            });
            timer.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.draw(pathShape);

            AffineTransform at = new AffineTransform();

            if (pos != null) {

                Rectangle bounds = car.getBounds();
                at.rotate(angle, (bounds.width / 2), (bounds.width / 2));

                Path2D player = new Path2D.Double(car, at);

                g2d.translate(pos.getX() - (bounds.width / 2), pos.getY() - (bounds.height / 2));
                g2d.draw(player);

            }

            g2d.dispose();
        }

        // In radians...
        protected double angleTo(Point2D from, Point2D to) {
            double angle = Math.atan2(to.getY() - from.getY(), to.getX() - from.getX());
            return angle;
        }

    }

}