当前位置: 首页 > 知识库问答 >
问题:

LibGDX路径(CatmullRomSpline)恒速

刘选
2023-03-14

我正在尝试使用LibGDX CatmullRomSpline在路径上实现恒定速度,但在使其工作时遇到了问题。我曾多次尝试研究这个话题,包括阅读LibGDX维基,但他们对实现恒定速度的解释没有真正意义,我无法让他们的方法发挥作用。https://github.com/libgdx/libgdx/wiki/Path-interface-

在我的例子中,我有几个与球的速度一致的视觉辅助工具,屏幕底部的条随着速度的增加而增加,颜色也随着速度的增加而从白色变为红色。

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

我对恒定速度的想法是根据路径的总长度计算速度(使用样条曲线上的approxLength(1000)方法),然后使用导数函数确定给定时刻的实际速度,以及调整发送到花键的百分比值,以补偿速度变化,从而使速度恒定。然而,我不太明白导数函数实际上代表什么。我之前发布了一个关于导数函数的问题,但根据我收到的一条评论,我想问一个关于实现恒定速度的问题可能会更容易。这是我之前关于导数函数的问题:LibGDX-CatmullRomSpline导数的意义?

在我的例子中,任何关于如何实现恒定速度的想法(或者解释CatmullRomSpline的导数函数实际上代表什么,以便我更好地理解如何使用它)都将受到极大的赞赏。

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

下面是我的示例代码:

桌面发射器。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);
    }
}

测验爪哇:

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

我的路径。爪哇:

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个答案

松旭
2023-03-14

由于导数是样条线位置的变化率,它实际上是“速度”,当样条线从基础数据点弯曲时,它必须“加速”,以使计算出的样条线及时到达下一个数据点,因此必须将该速度除以,以感知视觉恒定速度。

你没有得到一个恒定的速度,因为你仍然用增量来增加你的时间变量,而不是用增量除以变化率(导数)。您应该在每帧的百分比变量中添加一个变量量,而不是通过沿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;

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

在样条曲线上迭代以找到派生的平均值平均:

 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;
 类似资料:
  • 我知道有很多关于JAVA_HOME的问题,我以前当然也研究过它。我多年来一直在设置和运行java代码。 我认为libgdx需要一个jdk bin的路径,而不是一个jre bin。当我试图创建一个小测试文件时,我收到了以下错误: 错误:JAVA_HOME设置为无效目录:C:\Program Files\Java\JRE7\bin java_home=c:\program files\java\jre

  • 进入到某个目录的下面,去编辑在某个位置上的文件。你应该了解文件与目录的路径在命令行界面下的表示方法。 层级 目录的层级关系一般使用 / 来表示,Windows 上用的是 \ 。 macOS / Linux /Users/wanghao/desktop Windows C:\Users\wanghao\desktop 上面都表示的是 desktop 这个东西的路径。在 macOS / Linux

  • 路径分为绝对路径和相对路径。 绝对路径的起始点为根目录 / ,例如 /usr/local/bin 就是绝对路径,它指向系统中一个绝对的位置,不受其它因素影响。 相对路径的起始点为当前目录,如果您现在位于 /usr 目录,那么相对路径 local/bin 所指示的位置为 /usr/local/bin 也就是说,相对路径所指示的位置,除了相对路径本身,还受到当前位置的影响。例如 Linux 系统中常见

  • Vim是一个文本编辑器,而文本编辑器(经常)处理文本文件。文本文件储存在文件系统中, 而我们使用路径来描述文件。Vimscript有一些内置的方法会在你需要处理路径时帮上大忙。 绝对路径 有时外部脚本也需要获取特定文件的绝对路径名。执行下面的命令: :::vim :echom expand('%') :echom expand('%:p') :echom fnamemodify('foo.txt'

  • 问题内容: 如果使用绝对路径,则无法将整个目录移动到新位置。如果使用相对路径,则无法将单个文件移动到新位置。 这里有什么解决方案?您是否设置了一个包含根路径并从那里开始的配置文件?还是您有类似的规则:永不移动文件? 我在某些项目中看到人们使用dirname( FILE )。我的意思是,为什么不简单地将其删除,因为目录名还是相对的(取决于文件所在的位置)? 问题答案: 您应该使用一个配置文件,该配置

  • 首先,我不完全确定这是正确的问题。基本上,我的最终目标是生成一个可以操作一组。docx文件的程序,以便对每个文件进行小的更改。在我看来,docx4j是实现这一目标的最佳方式。但是,我从来没有使用过提供的库之外的库。我首先试图破译手册中提供的所有信息,然后告诉我需要SLF4J才能使用Docx4J。 从这一点来看,我想我做错了什么。我很确定我知道我想写的程序背后的伪逻辑,但我不确定如何写它。我还没有做