首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Java中创建两点之间的圆弧以进行插值

在Java中创建两点之间的圆弧以进行插值
EN

Stack Overflow用户
提问于 2014-03-25 06:08:41
回答 2查看 942关注 0票数 0

我有一个我正在制作的自上而下的游戏,我希望我的敌人能够在屏幕上以弧形移动。现在,它们在屏幕的两个边缘之间以直线方式移动。我在一条边上生成一个开始位置,然后在屏幕上的某个位置找到一个随机位置,并计算出移动速度,将角度的sin/cos乘以它们的速度变量。

我想用这些点在它们之间产生一些弧线,然后用它来移动我的敌人。我想也许一些样条线可以做到这一点,但我不完全确定如何创建一个,更重要的是如何使用它来插值我的角色。我认为在这一点上,这更像是一个数学问题,而不是编程,但我希望有人能帮上忙。谢谢。

EN

Stack Overflow用户

发布于 2014-03-25 07:16:19

当您打算使用样条线时,可以使用Java语言中已有的Path2D类。您可以通过以下方式组装任意路径

移动到某一直线段,一条二次曲线,一条三次曲线段,一段三次曲线,一段三次曲线,

因此,组装这条路径应该很简单:您只需创建一条二次曲线,该曲线从屏幕左边界上的任意点开始,到屏幕右边界上的任意点结束。作为控制点(两端),您可以在屏幕中心的任意位置使用一个点。

(顺便说一下:当您设法将路径表示为通用Path2D时,您可能会想象到,在为敌人设计路径时,您有相当大的自由度。它们可以绕圈或之字形运行,就像你喜欢的那样……)

这里可能更棘手的是让敌人遵循这条道路。

第一步还不是很棘手:您可以使用PathIterator沿着这条路走下去。但是这个PathIterator只会返回一个线段,即二次曲线。这可以通过创建一个展平的PathIterator来缓解。这会将所有曲线转换为线段(分辨率可以很高,因此您不会注意到任何拐角)。

然而,现在来了真正棘手的部分:当迭代这些线段时,移动速度可能会有所不同:根据原始二次曲线的曲率,可能会创建更多或更少的线段。在最坏的情况下,当所有3个点都在一条线上时,将只创建一条线段,并且敌人将在单个步骤中穿过整个屏幕。所以你必须确保以恒定的速度遍历这条路径。当迭代路径时,你必须计算你已经走了多远,并且可能在路径的两点之间插入一个位置。

我很快组装了一个例子。这当然不是万无一失的,但可以作为一个起点。

代码语言:javascript
运行
复制
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;


public class SplineMovementTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static PathFollower pathFollower;

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new BorderLayout());

        final Random random = new Random(0);

        final SplineMovementPanel p = new SplineMovementPanel();

        JButton generateButton = new JButton("Generate");
        generateButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                Shape spline = generateSpline(p,
                    random.nextDouble(),  
                    random.nextDouble(),  
                    random.nextDouble());
                p.setSpline(spline);
                pathFollower = new PathFollower(spline);
                p.repaint();
            }
        });
        frame.getContentPane().add(generateButton, BorderLayout.NORTH);
        startAnimation(p);

        frame.getContentPane().add(p, BorderLayout.CENTER);
        frame.setSize(800, 800);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static Shape generateSpline(
        JComponent c, double yLeft, double yCenter, double yRight)
    {
        Path2D spline = new Path2D.Double();
        double x0 = 0;
        double y0 = yLeft * c.getHeight();
        double x1 = c.getWidth() / 2;
        double y1 = yCenter * c.getHeight();
        double x2 = c.getWidth();
        double y2 = yRight * c.getHeight();
        spline.moveTo(x0, y0);
        spline.curveTo(x1, y1, x1, y1, x2, y2);
        return spline;
    }

    private static void startAnimation(final SplineMovementPanel p)
    {
        Timer timer = new Timer(20, new ActionListener()
        {
            double position = 0.0;

            @Override
            public void actionPerformed(ActionEvent e)
            {
                position += 0.005;
                position %= 1.0;
                if (pathFollower != null)
                {
                    Point2D point = pathFollower.computePointAt(
                        position * pathFollower.getPathLength());
                    p.setObjectLocation(point);
                }
            }
        });
        timer.start();
    }
}

class PathFollower
{
    private final List<Point2D> points;
    private final double pathLength;

    PathFollower(Shape spline)
    {
        points = createPointList(spline);
        pathLength = computeLength(points);
    }

    public double getPathLength()
    {
        return pathLength;
    }

    Point2D computePointAt(double length)
    {
        if (length < 0)
        {
            Point2D p = points.get(0);
            return new Point2D.Double(p.getX(), p.getY());
        }
        if (length > pathLength)
        {
            Point2D p = points.get(points.size()-1);
            return new Point2D.Double(p.getX(), p.getY());
        }
        double currentLength = 0;
        for (int i=0; i<points.size()-1; i++)
        {
            Point2D p0 = points.get(i);
            Point2D p1 = points.get(i+1);
            double distance = p0.distance(p1);
            double nextLength = currentLength + distance;
            if (nextLength > length)
            {
                double rel = 1 - (nextLength - length) / distance;
                double x0 = p0.getX();
                double y0 = p0.getY();
                double dx = p1.getX() - p0.getX();
                double dy = p1.getY() - p0.getY();
                double x = x0 + rel * dx;
                double y = y0 + rel * dy;
                return new Point2D.Double(x,y);
            }
            currentLength = nextLength;
        }
        Point2D p = points.get(points.size()-1);
        return new Point2D.Double(p.getX(), p.getY());
    }

    private static double computeLength(List<Point2D> points)
    {
        double length = 0;
        for (int i=0; i<points.size()-1; i++)
        {
            Point2D p0 = points.get(i);
            Point2D p1 = points.get(i+1);
            length += p0.distance(p1);
        }
        return length;
    }

    private static List<Point2D> createPointList(Shape shape)
    {
        List<Point2D> points = new ArrayList<Point2D>();
        PathIterator pi = shape.getPathIterator(null,  0.1);
        double coords[] = new double[6];
        while (!pi.isDone())
        {
            int s = pi.currentSegment(coords);
            switch (s)
            {
                case PathIterator.SEG_MOVETO:
                    points.add(new Point2D.Double(coords[0], coords[1]));

                case PathIterator.SEG_LINETO:
                    points.add(new Point2D.Double(coords[0], coords[1]));
            }
            pi.next();
        }
        return points;
    }

}


class SplineMovementPanel extends JPanel
{
    void setSpline(Shape shape)
    {
        this.spline = shape;
    }

    void setObjectLocation(Point2D objectLocation)
    {
        this.objectLocation = objectLocation;
        repaint();
    }
    private Shape spline = null;
    private Point2D objectLocation = null;


    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);

        if (spline != null)
        {
            g.setColor(Color.BLACK);
            g.draw(spline);
        }

        if (objectLocation != null)
        {
            g.setColor(Color.RED);
            int x = (int)objectLocation.getX()-15;
            int y = (int)objectLocation.getY()-15;
            g.fillOval(x, y, 30, 30);
        }
    }


}
票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22621638

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档