libGDX: Как реализовать плавное движение игрового персонажа на основе плитки/сетки?

В страхе изобретать велосипед я задаюсь вопросом:

Каков наилучший подход к реализации плавного движения игрового персонажа на основе сетки на плиточной (2D) карте сверху вниз с помощью libGDX?

Персонаж должен продолжать плавно перемещаться между плитками до тех пор, пока нажата клавиша со стрелкой (или событие касания происходит в определенном направлении персонажа), и должен заканчиваться в позиции сетки при отпускании клавиши / касания. Движение должно быть независимым от частоты кадров.

Я был бы рад некоторым уже реализованным примерам, которые можно изучить и привести к правильному использованию API libGDX.


person Jens Piegsa    schedule 07.01.2014    source источник
comment
Я написал статью о плавном движении на основе плитки, надеюсь, она поможет paladin-t.github.io/articles/   -  person pipipi    schedule 18.11.2020


Ответы (2)


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

Предположим, ширина/высота вашего тайла равна 1, и вы хотите перемещать 1 тайл в секунду. Ваш пользователь нажал клавишу со стрелкой вправо. Затем вы просто устанавливаете targettile на плитку справа от игрока.

if(targettile!=null){
    yourobject.position.x += 1*delta;
    if(yourobject.position.x>=targettile.position.x){
        yourobject.position.x = targettile.position.x;
        targettile = null;
    }
}

Этот код упрощен только для правильного движения, вам нужно сделать его и для других направлений.
Не забудьте снова опросить ввод, если игрок не движется.

Изменить:

InputPolling для ключей:

if (Gdx.input.isKeyPressed(Keys.DPAD_RIGHT)){

InputPolling для касаний (cam — это ваша камера, а touchPoint — это Vector3 для хранения непроецированных координат касания и moverightBounds (libgdx) Rectangle):

if (Gdx.input.isTouched()){
    cam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
    //check if the touch is on the moveright area, for example:
    if(moveRightBounds.contains(touchPoint.x, touchPoint.y)){
        // if its not moving already, set the right targettile here
    }
}

И никто уже не говорил об этом, вы получаете дельту как параметр в методе render или вы можете получить его в любом другом месте, используя:

Gdx.graphics.getDeltatime();

Использованная литература:

person Lestat    schedule 07.01.2014
comment
Спасибо за вашу помощь. Не могли бы вы объяснить немного подробнее, откуда вызывать этот код и как выполнять опрос ввода? Кроме того, я не уверен, как вычислить delta в соответствии с изменяющейся частотой кадров. - person Jens Piegsa; 07.01.2014
comment
@JensPiegsa Вы получаете дельту от LibGDX в качестве параметра в ваших методах рендеринга (). В противном случае вы можете получить его через Gdx.graphics.getDeltaTime(). - person noone; 07.01.2014
comment
Отредактировал мой ответ :) вы вызываете это в методе рендеринга (каждый кадр) - person Lestat; 07.01.2014
comment
Еще раз спасибо за важные подсказки, которые действительно привели к рабочему решению. - person Jens Piegsa; 08.01.2014

Это только для одного измерения, но я надеюсь, что вы поняли идею, проверив клавиши направления и добавив/вычитая 1, а затем приведя его к целому (или полу), вы получите следующую плитку. Если вы отпустите клавишу, у вас все еще будет недостигнутая цель, и сущность будет продолжать двигаться, пока не достигнет целевой плитки. Я думаю, это будет выглядеть примерно так:

void update()(
    // Getting the target tile
    if ( rightArrowPressed ) {
        targetX = (int)(currentX + 1); // Casting to an int to keep 
                                       // the target to next tile
    }else if ( leftArrowPressed ){
        targetX = (int)(currentX - 1);
    }

    // Updating the moving entity
    if ( currentX < targetX ){
        currentX += 0.1f;
    }else if ( currentX > targetX ){
        currentX -= 0.1f;
    }
}
person Per-Erik Bergman    schedule 07.01.2014
comment
Это именно то, на что я ответил несколько часов назад ... и здесь используется фиксированный шаг вместо использования времени, прошедшего между кадрами, для достижения независимого от кадров движения. - person Lestat; 07.01.2014
comment
Извините, ваш ответ не был виден для меня, когда я разместил свой ответ. - person Per-Erik Bergman; 07.01.2014