基于平滑速度的运动,持续时间可预测

时间:2015-03-17 00:51:50

标签: java unity3d

任何人都有一个很好的算法,可以在任何语言中从2D a -> b点获得平滑但可预测的移动?

我需要有一个功能设置每帧的速度:

function GetVel(current_pos : Vector2, dest_pos : Vector2, current_vel : Vector2)
{
 var new_vel : Vector2d;
 .......
 return new_vel;
}

和相应的:

function GetDestTime(current_pos : Vector2, dest_pos : Vector2, current_vel : Vector2 )
{
 var duration : float;
 .......
 return duration;
}

简单地使用加速导致大量滑动,因此可以预测精确定位时间的一些好的smoothDamp算法是我需要的。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

假设v(0)= 0且v(T)= 0,v(t)是二次函数,t = T / 2时的最大值。

因此,我们可以采用表格

由于该点在T秒内移动L,因此将v(t)从0整合到T必须给出L.所以,我们可以得到另一个等式,

求解这些方程式,

使用这些a和b,您可以计算当前的速度。

这是相当长的,但我做了一个Java玩具来实现这个目标。请检查一下!

import java.awt.*;
import javax.swing.*;

public class MovePoint extends Canvas implements Runnable {
    public static void main(String... args) {
        Thread thread = new Thread(new MovePoint());
        thread.start();
    }

    private static final int WIDTH = 500;
    private static final int HEIGHT = 500;

    public MovePoint() {
        super();
        this.setBackground(Color.WHITE);
        this.setForeground(Color.BLACK);
        this.setSize(WIDTH, HEIGHT);

        JFrame f = new JFrame("Move Point");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setVisible(true);
    }

    private Point V;
    private Point S = new Point(50, 50);
    private Point E = new Point(450, 450);
    private double duration = 5.0;
    private double dt = 0.03;
    private Image buffer;
    private Graphics gBuf;

    public void run() {
        double t = 0.0;
        V = S.copy();
        while (t < duration) {
            V = Point.add(V, calcVelocity(V, S, E, t, duration).scale(dt));
            t += dt;
            repaint();
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.exit(0);
    }

    public void paint(Graphics g) {
        if (gBuf == null) {
            buffer = createImage(WIDTH, HEIGHT);
            gBuf = buffer.getGraphics();
        }
        gBuf.setColor(Color.WHITE);
        gBuf.fillRect(0, 0, WIDTH, HEIGHT);
        gBuf.setColor(Color.BLACK);
        gBuf.fillOval((int)(V.x - 5), (int)(V.y - 5), 11, 11);
        g.drawImage(buffer, 0, 0, this);
    }

    public void update(Graphics g) {
        paint(g);
    }

    public Point calcVelocity(Point current, Point start, Point goal, double t, double T) {
        double L = Point.distance(start, goal);
        double a = -6.0 / (T * T * T);
        double b =  3.0 / (2.0 * T);

        double s = (t - 0.5 * T);
        double v = a * s * s + b;
        return Point.subtract(goal, start).scale(v);
    }
}

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public Point copy() {
        return new Point(x, y);
    }

    public static double distance(Point p, Point q) {
        double dx = p.x - q.x;
        double dy = p.y - q.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

    public static Point add(Point p, Point q) {
        return new Point(p.x + q.x, p.y + q.y);
    }

    public static Point subtract(Point p, Point q) {
        return new Point(p.x - q.x, p.y - q.y);
    }

    public Point scale(double s) {
        return new Point(x * s, y * s);
    }
}