Мне интересно, как обычно создаются механизмы манипуляции временем в играх. Я особенно заинтересован в обращении времени (вроде как в последнем SSX или Prince of Persia).
Игра представляет собой 2D шутер сверху вниз.
Механизм, который я пытаюсь разработать / реализовать, имеет следующие требования:
1) Действия сущностей, кроме персонажа игрока, являются полностью детерминированными.
- Действие, которое предпринимает объект, основано на прогрессирующих кадрах с момента начала уровня и / или позиции игрока на экране.
- Объекты создаются в установленное время на уровне.
2) Обратное время работает, возвращаясь обратно в реальном времени.
- Действия игрока также меняются местами, оно повторяет действия игрока. Игрок не имеет контроля в обратном времени.
- Время, затрачиваемое на реверсирование, не ограничено, при желании мы можем полностью вернуться к началу уровня.
Например:
Кадры 0-50: в течение этого времени игрок перемещается на 20 единиц вперед в течение 20 кадра. Враг 1 перемещается влево на 10 единиц в течение кадра 30-40. Игрок стреляет пулей в кадре 45. Пуля движется на 5 вперед (45-50) и убивает врага 1 в кадр 50
Изменение этого положения приведет к воспроизведению в реальном времени: в течение этого времени игрок перемещается назад на 20 единиц. Враг 1 возрождается в кадре 50. Пуля возвращается в кадре 50. Пуля движется назад 5 и исчезает (50-45) Враг перемещается влево 10 (40-30) Враг удаляется в кадр 20.
Просто глядя на движение, у меня были некоторые идеи о том, как этого добиться, я подумал о том, чтобы иметь интерфейс, который изменял поведение в то время, когда время продвигалось или изменялось. Вместо того, чтобы делать что-то вроде этого:
void update()
{
movement += new Vector(0,5);
}
Я бы сделал что-то вроде этого:
public interface movement()
{
public void move(Vector v, Entity e);
}
public class advance() implements movement
{
public void move(Vector v, Entity e)
{
e.location += v;
}
}
public class reverse() implements movement
{
public void move(Vector v, Entity e)
{
e.location -= v;
}
}
public void update()
{
moveLogic.move(new vector(5,0));
}
Однако я понял, что это не будет оптимальной производительностью и быстро усложнится для более продвинутых действий (таких как плавное движение по изогнутым траекториям и т. Д.).
Ответы:
Возможно, вы захотите взглянуть на шаблон команды .
В основном каждое обратимое действие, которое предпринимают ваши сущности, реализуется как командный объект. Все эти объекты реализуют как минимум 2 метода: Execute () и Undo (), плюс все, что вам нужно, например, свойство метки времени для правильной синхронизации.
Всякий раз, когда ваша сущность выполняет обратимое действие, вы сначала создаете соответствующий объект команды. Вы сохраняете его в стеке Undo, затем добавляете его в игровой движок и запускаете его. Когда вы хотите изменить время, вы выталкиваете действия из верхней части стека и вызываете их метод Undo (), который делает противоположное методу Execute (). Например, в случае прыжка из точки A в точку B вы выполняете переход с B на A.
После того, как вы добавили действие, сохраните его в стеке «Вернуть», если хотите идти вперед и назад по желанию, точно так же, как функцию отмены / повтора в текстовом редакторе или программе рисования. Конечно, ваша анимация также должна поддерживать режим «перемотки» для воспроизведения в обратном направлении.
Для большего количества изменений в игровом дизайне, пусть каждая сущность хранит свои действия в своем собственном стеке, так что вы можете отменить / повторить их независимо друг от друга.
У шаблона команд есть и другие преимущества: например, создание рекордера воспроизведения довольно просто, так как вам просто нужно сохранить все объекты из стеков в файл, а во время воспроизведения просто подать его в игровой движок один за другим. один.
источник
Вы могли бы взглянуть на Шаблон Memento; Его основное намерение - реализовать операции отмены / возврата путем отката состояния объекта, но для некоторых видов игр этого должно быть достаточно.
Для игры в режиме реального времени вы можете рассматривать каждый кадр ваших операций как изменение состояния и сохранять его. Это простой подход для реализации. Альтернатива состоит в том, чтобы перехватывать, когда состояние объекта изменяется. Например, обнаружение изменения сил, действующих на твердое тело. Если вы используете свойства для получения и установки переменных, это также может быть относительно простой реализацией, трудной частью является определение момента отката состояния, так как это не будет одинаковым временем для каждого объекта (вы можете сохранить время отката в виде числа кадров от начала системы).
источник
В вашем конкретном случае обработка отката путем перемотки движения должна работать нормально. Если вы используете какую-либо форму поиска пути с единицами ИИ, просто обязательно пересчитайте ее после отката, чтобы избежать перекрытия юнитов.
Проблема в том, как вы справляетесь с самим движением: приличный физический движок (двухмерный шутер с верхом вниз хорошо подойдет с очень простым), который отслеживает информацию о последних шагах (включая позицию, чистую силу и т. Д.), Предоставит прочная основа. Затем, решив максимальный откат и степень детализации для шагов отката, вы должны получить желаемый результат.
источник
Пока это интересная идея. Я бы посоветовал против этого.
Воспроизведение форвардов игры работает нормально, потому что операция всегда будет одинаково влиять на состояние игры. Это не означает, что обратная операция дает вам исходное состояние. Например, оцените следующее выражение на любом языке программирования (отключите оптимизацию)
По крайней мере, в C и C ++ он возвращает false. Хотя разница может быть небольшой, представьте, сколько ошибок может накапливаться при 60 кадрах в секунду за 10 секунд секунд. Будут случаи, когда игрок только что-то пропускает, но поражает его, пока игра переигрывается задом наперед.
Я бы рекомендовал хранить ключевые кадры каждые полсекунды. Это не займет слишком много памяти. Затем вы можете либо интерполировать между ключевыми кадрами, или, что еще лучше, смоделировать время между двумя ключевыми кадрами, а затем воспроизвести его в обратном направлении.
Если ваша игра не слишком сложна, просто сохраняйте ключевые кадры состояния игры 30 раз в секунду и играйте в обратном направлении. Если бы у вас было 15 объектов с 2D-позицией, потребуется 1,5 минуты, чтобы получить МБ без сжатия. Компьютеры имеют гигабайты памяти.
Так что не переусердствуйте, переиграть игру будет нелегко, и это вызовет много ошибок.
источник