До применения экстраполяции к движению моего спрайта, мое столкновение работало отлично. Однако после применения экстраполяции к движению моего спрайта (для сглаживания) столкновение больше не работает.
Вот как все работало до экстраполяции:
Однако после того, как я реализую свою экстраполяцию, процедура столкновения прерывается. Я предполагаю, что это потому, что он действует на новую координату, которая была создана подпрограммой экстраполяции (которая находится в моем вызове рендеринга).
После того, как я применяю свою экстраполяцию
Как исправить это поведение?
Я попытался поставить дополнительную проверку столкновений сразу после экстраполяции - похоже, это действительно решает многие проблемы, но я исключил это, потому что о логике в моем рендеринге не может быть и речи.
Я также попытался сделать копию позиции spritesX, экстраполировать ее и рисовать, используя ее, а не оригинал, таким образом, оставляя оригинал без изменений для логики, чтобы подобрать - это кажется лучшим вариантом, но он все еще производит некоторые странные эффекты при столкновении со стенами. Я уверен, что это не правильный способ справиться с этим.
Я нашел пару подобных вопросов здесь, но ответы не помогли мне.
Это мой экстраполяционный код:
public void onDrawFrame(GL10 gl) {
//Set/Re-set loop back to 0 to start counting again
loops=0;
while(System.currentTimeMillis() > nextGameTick && loops < maxFrameskip){
SceneManager.getInstance().getCurrentScene().updateLogic();
nextGameTick+=skipTicks;
timeCorrection += (1000d/ticksPerSecond) % 1;
nextGameTick+=timeCorrection;
timeCorrection %=1;
loops++;
tics++;
}
extrapolation = (float)(System.currentTimeMillis() + skipTicks - nextGameTick) / (float)skipTicks;
render(extrapolation);
}
Применение экстраполяции
render(float extrapolation){
//This example shows extrapolation for X axis only. Y position (spriteScreenY is assumed to be valid)
extrapolatedPosX = spriteGridX+(SpriteXVelocity*dt)*extrapolation;
spriteScreenPosX = extrapolationPosX * screenWidth;
drawSprite(spriteScreenX, spriteScreenY);
}
редактировать
Как я уже упоминал выше, я попытался сделать копию координат спрайта специально для рисования ... у него есть свои проблемы.
Во-первых, независимо от копирования, когда спрайт движется, он супергладкий, когда он останавливается, он слегка колеблется влево / вправо - поскольку он все еще экстраполирует свою позицию на основе времени. Это нормальное поведение и можем ли мы его «выключить», когда спрайт останавливается?
Я попытался иметь флаги для левого / правого и только экстраполяции, если любой из них включен. Я также попытался скопировать последнюю и текущую позиции, чтобы увидеть, есть ли разница. Однако, что касается столкновения, это не помогает.
Если пользователь нажимает, скажем, правая кнопка и спрайт движется вправо, когда он ударяется о стену, если пользователь продолжает удерживать правую кнопку нажатой, спрайт будет продолжать анимацию вправо, пока он остановлен стеной ( следовательно, фактически не перемещается), тем не менее, поскольку правильный флаг все еще установлен, а также потому, что процедура столкновения постоянно перемещает спрайт из стены, в коде (а не в проигрывателе) все еще показывается, что спрайт все еще движется, и поэтому экстраполяция продолжается. Итак, что бы игрок увидел, это спрайт «статичный» (да, он оживляет, но на самом деле он не перемещается по экрану), и время от времени он сильно трясется, когда экстраполяция пытается это сделать… .. надеюсь, это поможет
Ответы:
Я не могу оставить комментарий, поэтому я опубликую это как ответ.
Если я правильно понимаю проблему, она выглядит примерно так:
Я могу придумать 3 возможных решения. Я перечислю их в том порядке, который наиболее желателен, по крайней мере, ИМХО.
Пример кода для # 2.
Я думаю, что № 2, вероятно, будет самым быстрым и легким для запуска, хотя № 1 представляется более логически точным решением. В зависимости от того, как вы обрабатываете свое дельта-время, решение № 1 может быть практически одинаково разбито большой дельтой, и в этом случае вам, возможно, придется использовать и № 1, и № 2 вместе.
РЕДАКТИРОВАТЬ: я неправильно понял ваш код ранее. Циклы предназначены для максимально быстрого рендеринга и обновления с заданным интервалом. Вот почему вы должны интерполировать позицию спрайта, чтобы обработать случай, когда вы рисуете больше, чем обновление. Однако, если цикл отстает, то вы будете опрашивать об обновлении до тех пор, пока вы не будете захвачены или не пропустите максимальное количество кадров.
При этом единственная проблема заключается в том, что объект движется после столкновения. В случае столкновения объект должен перестать двигаться в этом направлении. Таким образом, если происходит столкновение, установите его скорость равной 0. Это должно остановить функцию рендеринга от дальнейшего перемещения объекта.
источник
Похоже, вам нужно полностью отделить рендеринг и обновление физики. Обычно базовое моделирование будет выполняться с дискретными временными шагами, и частота никогда не изменится. Например, вы можете имитировать движение вашего шарика каждую 1/60 секунды, и все.
Чтобы обеспечить переменную частоту кадров, код рендеринга должен работать на переменной частоте, но любое моделирование должно по-прежнему выполняться с фиксированным временным шагом. Это позволяет графике считывать память из симуляции как доступную только для чтения, и позволяет настроить интерполяцию вместо экстраполяции.
Поскольку экстраполяция пытается предсказать, где будут находиться будущие значения, внезапные изменения в движении могут привести к огромным ошибкам экстраполяции. Вместо этого лучше визуализировать вашу сцену вокруг кадра позади симуляции и интерполировать между отдельными известными позициями.
Если вы хотите увидеть некоторые детали реализации, я уже написал короткий раздел на эту тему в статье здесь . Пожалуйста, смотрите раздел под названием «Временные шаги».
Вот важный код псевдо из статьи:
RenderGame
Функция представляет наибольший интерес. Идея состоит в том, чтобы использовать интерполяцию между позициями дискретного моделирования. Код рендеринга может создавать собственные копии данных симуляции только для чтения и использовать временное интерполированное значение для рендеринга. Это даст вам очень плавное движение без каких-либо глупых проблем, таких как то, что вы, похоже, испытываете!источник