在 Java 中旋转多边形

Rotating a polygon in Java

我正在编写的程序在屏幕上绘制了多颗星星,并为它们指定了随机方向和速度。星星将从面板的边缘反弹并留在内部。我需要让星星在移动时旋转。我已经尝试了很多东西,但我无法弄清楚。下面是我用来绘制星星并移动它们的代码。

附加信息:

-星星在一个名为 "stars"

的集合中

-我写了两个class,"Star"和"MyJPanel"

设置点数:(在星class)

for (double current = 0; current < nPoints; current += 1)
{
    i = (int)current;
    int[] X = new int[nPoints * 2];
    int[] Y = new int[nPoints * 2];
    cosX = -(Math.cos(current*((2*Math.PI)/(nPoints)))*radius[i % 2]);
    sinY = -(Math.sin(current*((2*Math.PI)/(nPoints)))*radius[i % 2]);
    X[i] = (int) cosX+x;
    Y[i] = (int) sinY+y;
    addPoint(X[i], Y[i]);
}

移动方法:(星class)

public void move(int width, int height)
{
    if (location.x <= radius[0] || location.x >= width - radius[0])
    {
        xIncr = -xIncr;
    }

    if (location.y <= radius[0] || location.y >= height - radius[0])
    {
        yIncr = -yIncr;
    }
    translate(xIncr, yIncr);
    location.setLocation(location.x + xIncr, location.y + yIncr);
    xInc = xIncr;
}

画星星:(在 MyJPanel class)

public void paintComponent(Graphics g)
{
    super.paintComponent(g);

        for(int i = 0; i < stars.size(); i++)
    {
        g2d = (Graphics2D) g;
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, stars.get(i).getAlpha()));
        g2d.setColor(stars.get(i).getColor());
        g2d.fillPolygon(stars.get(i));

        if(stars.get(i).alpha == 0)
        {
            stars.remove(stars.indexOf(stars.get(i)));
        }
    }
}

如果需要更多代码或信息,请告诉我,谢谢!

我会看看Working with Geometry and Transforming Shapes, Text, and Images

基本上,我创建了一个自定义 Path2D 形状来代表我的开始。这个 class 带有一些额外的信息,包括它的 x/y 偏移和旋转。然后它提供了一个辅助方法来根据这些属性创建此形状的转换实例,例如...

public Shape getTransformedInstance() {
    AffineTransform at = new AffineTransform();
    Rectangle bounds = getBounds();
    at.rotate(Math.toRadians(angle), x + (bounds.width / 2), y + (bounds.height / 2));
    at.translate(x, y);
    return createTransformedShape(at);
}

基本上,这就是奇迹发生的地方。

有一个简单的 Swing Timer,它将增量应用于位置和旋转。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
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.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RotateShape {

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

    public RotateShape() {
        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 Star star;
        private double rotationDelta = 5d;
        private int xDelta = 0;
        private int yDelta = 0;

        public TestPane() {
            star = new Star(50, 50);
            star.moveLocatioBy(75, 75);

            Random rnd = new Random();
            xDelta = rnd.nextInt(4) + 1;
            yDelta = rnd.nextInt(4) + 1;

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    star.moveLocatioBy(xDelta, yDelta);
                    Rectangle bounds = star.getBounds();
                    int x = star.getX();
                    int y = star.getY();

                    boolean bounced = false;
                    if (x < 0) {
                        x = 0;
                        xDelta *= -1;
                        bounced = true;
                    } else if (x + bounds.width > getWidth()) {
                        x = getWidth() - bounds.width;
                        xDelta *= -1;
                        bounced = true;
                    }
                    if (y < 0) {
                        y = 0;
                        yDelta *= -1;
                        bounced = true;
                    } else if (y + bounds.height > getHeight()) {
                        y = getHeight() - bounds.height;
                        yDelta *= -1;
                        bounced = true;
                    }
                    if (bounced) {
                        rotationDelta *= -1;
                    }

                    star.rotateByDegrees(rotationDelta);
                    star.setLocation(x, y);
                    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.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            Shape shape = star.getTransformedInstance();
            g2d.setColor(Color.BLUE);
            g2d.fill(shape);
            g2d.setColor(Color.RED);
            g2d.draw(shape);
            g2d.dispose();
        }

    }

    public class Star extends Path2D.Double {

        private double angle = 0;
        private int x = 0, y = 0;

        public Star(int width, int height) {

            double heightPart = height / 3d;
            double widthPart = width / 3d;

            moveTo(width / 2, 0);
            lineTo(widthPart * 2, heightPart);
            lineTo(width, heightPart);
            lineTo(widthPart * 2, height / 2);
            lineTo(width, height);

            lineTo(width / 2, heightPart * 2);
            lineTo(0, height);
            lineTo(widthPart, height / 2);
            lineTo(0, heightPart);
            lineTo(widthPart, heightPart);

            closePath();
        }

        public double getAngle() {
            return angle;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public void moveLocatioBy(int xDelta, int yDelta) {
            this.x += xDelta;
            this.y += yDelta;
        }

        public void rotateByDegrees(double delta) {
            angle += delta;
        }

        public void setLocation(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public Shape getTransformedInstance() {
            AffineTransform at = new AffineTransform();
            Rectangle bounds = getBounds();
            at.rotate(Math.toRadians(angle), x + (bounds.width / 2), y + (bounds.height / 2));
            at.translate(x, y);
            return createTransformedShape(at);
        }

    }

}

扩展这个想法并不需要太多,这样每个开始都有自己的增量值和简单的 update 方法(在 Container 的 width/height 中传递), 所以你可以做很多星