简体   繁体   English

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

[英]Smooth velocity based movement with predictable duration

Anyone has a good algorithm for how to get a smooth but predictable movement from point a -> b in 2D in any language? 任何人都有一个好的算法,如何以任何语言从2D的a- a -> b点获得平稳但可预测的运动?

I need to have one function setting the velocity each frame: 我需要一个函数来设置每帧的速度:

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

and a corresponding: 和一个对应的:

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

Simply using acceleration leads up to lots of sliding so some good smoothDamp algorithm that can be predicted the exact dest time is what I need. 简单地使用加速度会导致大量的滑动,因此可以预测一些准确的目标时间,这是我需要的一种很好的smoothDamp算法。

Any ideas? 有任何想法吗?

Let's assume v(0) = 0 and v(T) = 0 and, v(t) is a quadratic function which the maximum value at t = T/2. 假设v(0)= 0且v(T)= 0,并且v(t)是一个二次函数,其最大值在t = T / 2。

Accordingly, we can assume the form, 因此,我们可以假设形式为

Since the point moves L within T seconds, integrating v(t) from 0 to T must give L. So, we can get another equation, 由于该点在L秒内移动了L,因此将v(t)从0积分到T必须得到L。因此,我们可以得到另一个方程,

Solving these equations gives, 解决这些方程式,

Using these a and b, you can compute the current velocity. 使用这些a和b,您可以计算当前速度。

It is rather long, but I made a Java toy to realize this. 时间很长,但是我制作了一个Java玩具来实现这一目标。 Please check it! 请检查一下!

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);
    }
}

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

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