LibGDX路径(CatmullRomSpline)恒速

时间:2015-09-19 06:55:58

标签: java libgdx spline calculus derivative

我正在尝试使用LibGDX CatmullRomSpline在路径上实现恒定速度,并且我在使其工作时遇到问题。我已经尝试过很多关于这个主题的研究,包括阅读LibGDX wiki,但他们对实现恒定速度的解释并没有真正意义,我无法让他们的方法发挥作用。 https://github.com/libgdx/libgdx/wiki/Path-interface-&-Splines 在我的情况下,导数值非常大(数百),因此当将0-1之间的数除以导数时,结果非常小并且运动非常慢并且仍然不恒定。所以我不确定他们的例子是如何运作的。

在我的例子中,我有一些视觉辅助工具与球的速度一致,随着速度的增加,屏幕底部的条形长度增加,随着速度的增加,颜色也会从白色变为红色。 / p>

在MyPath.java的act()方法中,我从[1]和[2]开始注释掉了两个部分。第一个是正常的,通过路径可变速度,第二个是我尝试使LibGDX wiki恒速工作失败。所以只需取消注释这两行就可以在两个版本之间切换。

我对恒速的想法包括根据路径的总长度计算速度(使用样条上的约长度(1000)方法),然后使用导数函数确定给定时刻的实际速度,以及调整发送到样条曲线的百分比值以补偿速度变化,以使速度保持恒定。但是,我不太明白衍生函数实际上代表什么。我之前发布了关于衍生函数的问题,但根据我收到的评论,我认为可能更容易询问实现恒定速度。这是我之前关于衍生函数的问题: LibGDX CatmullRomSpline Derivative Meaning?

关于如何在我的示例中实现恒定速度的任何想法(或解释CatmullRomSpline的衍生函数实际上代表什么,以便我可以更好地理解如何使用它)将不胜感激。

对于任何想要运行该程序的人,以下是我为我的示例创建的两个图像文件(将这些文件添加到assets文件夹的根目录): http://dropshots.com/Tekker/date/2015-09-19

这是我的示例代码:

DesktopLauncher.java:(将桌面窗口宽度和高度更改为1000)

public class DesktopLauncher {
    public static void main (String[] arg) {
        LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
        config.width = 1000;
        config.height = 1000;
        new LwjglApplication(new TEST(), config);
    }
}

TEST.java:

public class TEST extends Game {
    Stage stage;    
    MyPath path;

    @Override
    public void create () {
        stage = new Stage();
        stage.setViewport(new ScreenViewport(stage.getViewport().getCamera()));
        Gdx.input.setInputProcessor(stage);
        path = new MyPath(1000, 1000);
        stage.addActor(path);
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
    }

    @Override
    public void dispose(){
        stage.dispose();
        super.dispose();
    }
}

MyPath.java:

public class MyPath extends WidgetGroup {
    Image start, end, path, bar1, horizontal;
    float time, percent, dVal, pathLength, dMax=1000, cycle=6, maxPercent, deltaCycle;

    CatmullRomSpline<Vector2> catmull;
    Vector2 result = new Vector2();
    Vector2 previousResult = new Vector2(50,150);
    Vector2 derivative = new Vector2();
    Vector2 previousDerivative = new Vector2();
    Vector2[] points = {
        new Vector2(50,150), new Vector2(50,150),
        new Vector2(400,800), new Vector2(600,150), new Vector2(700,400),
        new Vector2(860,150), new Vector2(860,150)
    };

    boolean print = true;

    public MyPath(int width, int height){
        this.setSize(width, height);
        catmull = new CatmullRomSpline<Vector2>(points, false);

        createPath();
        createBar();

        pathLength = catmull.approxLength(1000);
    }

    @Override
    public void act(float delta){
        // [1] VARIABLE SPEED
        //time += delta;
        //percent = (time / cycle) % 1;

        // [2] CONSTANT SPEED FAIL!
        //catmull.derivativeAt(previousDerivative, percent);
        //time += delta;
        //percent = ((time / cycle) / previousDerivative.len() ) % 1;

        catmull.valueAt(result, percent);
        path.setPosition(result.x, this.getHeight() - result.y);

        updateSpeedVisuals();
        debugPrint();

        previousResult.set(result);
    }

    private void createPath(){
        start = new Image(new Texture("dot.png"));
        start.setColor(Color.GRAY);
        start.setPosition(50, this.getHeight() - 150);
        this.addActor(start);

        end = new Image(new Texture("dot.png"));
        end.setColor(Color.GRAY);
        end.setPosition(860, this.getHeight() - 150);
        this.addActor(end);

        path = new Image(new Texture("dot.png"));
        path.setColor(Color.WHITE);
        this.addActor(path);
    }

    private void createBar(){
        Texture texture = new Texture("ninepatch.png");
        int crop = (int)(texture.getWidth()/2)-1;
        NinePatch patch9 = new NinePatch(texture, crop, crop, crop, crop);
        bar1 = new Image(patch9);
        bar1.setColor(Color.GRAY);
        bar1.setPosition(5, this.getHeight()-900);
        this.addActor(bar1);
    }

    private void updateSpeedVisuals(){
        catmull.derivativeAt(derivative, percent);
        dVal = derivative.len() / dMax;
        path.setColor(1f, 1f-dVal, 1f-dVal, 1f);
        bar1.setWidth(derivative.len());
        bar1.setColor(1f, 1f-dVal, 1f-dVal, 1f);
    }

    private void debugPrint(){
        maxPercent = (percent > maxPercent) ? percent : maxPercent;
        if (maxPercent > percent){
            print = false;
        }
        if (print){
            String debugPrint = "";
            debugPrint = debugPrint + "pathLength=" + pathLength + "\t";
            debugPrint = debugPrint + "derivative=" + derivative.len() + "\t";
            System.out.println(debugPrint);
        }
    }
}

1 个答案:

答案 0 :(得分:6)

由于导数是样条位置的变化率,它确实是“速度”,当样条曲线远离基础数据点时,它必须加速&#39; 39;要使计算的样条曲线到达下一个数据时间点,必须将此速度分开以感知视觉恒定速度。

你没有获得恒定的速度,因为你仍然用delta而不是delta除以变化率(导数)来递增你的时间变量。您应该在每个帧的百分比变量中添加一个可变量,而不是按照Catmull-Rom样条曲线上单个点的导数修改所有内容。

而不是:

catmull.derivativeAt(previousDerivative, percent);
time += delta;
percent = ((time / cycle) / previousDerivative.len() ) % 1;

你应该:

catmull.derivativeAt(previousDerivative, percent);
percent += derivativeAverage / cycle * delta / previousDerivative.len();
percent %= 1;

你现在应该使用平均导数除以周期,因为你不能再单独使用循环作为每秒百分比变量。

迭代样条曲线以查找derivativeAverage的平均值:

 int samples = 100; //the higher the more accurate, however slower
 float derivativeAverage = 0;
 Vector2 out = new Vector2();
 for (float i=0;i<1;i+=1f/samples) {
     catmull.derivativeAt(out, i);
     derivativeAverage += out.len();
 }
 derivativeAverage /= samples;