Вопрос по derivative, libgdx, calculus, java, spline – LibGDX Path (CatmullRomSpline) Постоянная скорость

4

Я пытаюсь достичь постоянной скорости на пути, используя LibGDX CatmullRomSpline, и у меня возникают проблемы с его работой. Я много пытался исследовать эту тему, включая чтение вики LibGDX, но их объяснение достижения постоянной скорости не имеет смысла, и я не смог заставить их метод работать.https://github.com/libgdx/libgdx/wiki/Path-interface-&-Splines В моем случае значения производной очень велики (в сотнях), поэтому при делении числа между 0-1 и производной результат очень мал, а движение очень медленное и все еще не постоянное. Так что я не уверен, как именно работает их пример.

В моем примере у меня есть пара наглядных пособий, совпадающих со скоростью шара, полоса в нижней части экрана увеличивается по мере увеличения скорости, а цвет также меняется с белого на красный по мере увеличения скорости.

В методе act () MyPath.java я закомментировал два раздела, начиная с [1] и [2]. Первый нормальный с переменной скоростью на пути, а второй - моя неудачная попытка заставить постоянную скорость вики LibGDX работать. Так что просто откомментируйте эти строки для переключения между двумя версиями.

Моя идея постоянной скорости заключается в определении скорости на основе общей длины пути (с использованием метода приблизительной длины (1000) на сплайне), затем с использованием производной функции для определения фактической скорости в данный момент и корректировки процента значение, отправляемое в сплайн для компенсации изменений скорости с целью обеспечения постоянной скорости. Тем не менее, я не совсем понимаю, что на самом деле представляет производная функция. Я ранее опубликовал вопрос о производной функции, но, основываясь на полученном мной комментарии, я подумал, что вместо этого проще задать вопрос о достижении постоянной скорости. Вот мой предыдущий вопрос о производной функции:Производная LibGDX CatmullRomSpline Значение?

Будем весьма благодарны за любые идеи о том, как добиться постоянной скорости в моем примере (или объяснения того, что на самом деле представляет производная функция для 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   ответ
6

Поскольку производная - это скорость изменения положения сплайна, это действительно «скорость», и когда сплайн отклоняется от нижележащих точек данных, он должен «ускориться», чтобы вычисленный сплайн достиг следующей точки данных в Время, вы должны разделить эту скорость, чтобы воспринимать визуальную постоянную скорость.

Вы не получаете постоянную скорость, потому что вы все еще увеличиваете переменную времени на дельту вместо дельты, деленной на скорость изменения (производную). Вы должны добавлять переменную величину к процентной переменной в каждом кадре, вместо этого вы изменяли все по производной одной точки вдоль сплайна Катмулла-Рома.

Вместо:

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;
Позволь нампродолжить это обсуждение в чате. Johnathon Havens
Другой альтернативой может быть итерация по всему сплайну и нахождение среднего производного значения, я отредактирую ответ, чтобы включить что-то в этом направлении. Johnathon Havens
Я считаю, что вы могли бы использовать что-то вродеapproxLength(100) / cycle * delta / previousDerivative.len(), Единственное, я не уверен, как это будет взаимодействовать с производной, это может не дать ожидаемого результата. Дайте мне знать, что происходит, у меня нет Java-среды для тестирования на этом компьютере. Johnathon Havens
модуль 1 больше не нужен в этой строке, вам нужно запустить его как отдельную строкуpercent %= 1; Я отредактировал ответ, чтобы отразить Johnathon Havens

Похожие вопросы