Например, известная игра Flappy Bird, или что-то действительно сортирующее, - это игрок (в данном случае птица или камера, в зависимости от того, что вы предпочитаете), движущийся вперед или весь мир движется назад (птица меняет только положение Y и имеет постоянная позиция X)?
game-mechanics
platformer
Лендрит Ибрахими
источник
источник
Ответы:
Я немного не согласен с ответом Филиппа ; или хотя бы с тем, как он это представил. Создается впечатление, что лучше было бы передвигать мир вокруг игрока; когда все наоборот. Так вот мой собственный ответ ...
Оба варианта могут работать, но, как правило, плохая идея «инвертировать физику», перемещая мир вокруг игрока, а не игрока по всему миру.
Потеря производительности / растрата:
В мире обычно будет много объектов; многие, если не большинство, статичные или спящие. У игрока будет один или относительно немного объектов. Перемещение всего мира вокруг игрока означает перемещение всего на сцене, кроме игрока. Статические объекты, спящие динамические объекты, активные динамические объекты, источники света, источники звука и т. Д .; все должны быть перемещены.
Это (очевидно) значительно дороже, чем перемещать только то, что на самом деле движется (игрок, и, возможно, еще несколько вещей).
Ремонтопригодность и расширяемость:
Перемещение мира вокруг игрока делает мир (и все, что в нем) тем моментом, когда все происходит наиболее активно. Любая ошибка или изменение в системе означает, что потенциально все меняется. Это не хороший способ делать вещи; вы хотите, чтобы ошибки / изменения были как можно более изолированными, чтобы вы не получили неожиданного поведения там, где вы не внесли изменений.
Есть также много других проблем с этим подходом. Например, это нарушает многие предположения о том, как все должно работать в двигателе. Вы не сможете использовать динамические
RigidBody
для чего-либо, кроме игрока, например; поскольку объект с прикрепленным,RigidBody
не установленным кинематическим, будет вести себя неожиданно при настройке позиции / поворота / масштаба (что вы будете делать каждый кадр, для каждого объекта в сцене, кроме игрока 😨)Таким образом, ответ - двигать игрока только тогда!
Ну ... да и нет . Как упомянуто в ответе Филиппа, в играх с бесконечным бегущим (или в любой игре с большой бесшовной исследуемой областью) слишком большое расстояние от источника может в конечном итоге привести к появлению заметных FPPE ( ошибок точности с плавающей запятой ), и еще дальше, в конце концов, Переполнение числового типа, что может привести к сбою в игре или, по сути, к образованию дыма в игровом мире ... На стероидах! 😵 (потому что к этому моменту FPPE сделает игру уже на «нормальном» трещине)
Фактическое решение:
Не делай ни того, ни другого! Вы должны держать мир неподвижным и перемещать игрока вокруг него. Но «подкореним» и игрока, и мир, когда игрок начинает слишком далеко уходить от корня (позиция
[0, 0, 0]
) сцены.Если вы сохраняете относительное положение вещей (игрок по отношению к окружающему миру) и выполняете этот процесс в одном обновлении кадра, (реальный) игрок даже не заметит!
Для этого у вас есть два основных варианта:
Вот пример этого процесса в действии
Но как далеко это слишком далеко?
Если вы посмотрите на исходный код Unity, они используют
1e-5
(0.00001
) в качестве основы для рассмотрения двух значений с плавающей запятой «равными» внутриVector2
иVector3
(типы данных, отвечающие за положение объектов, [euler-] повороты и масштабирование). Поскольку потеря точности с плавающей точкой происходит в обоих направлениях от нуля, можно с уверенностью предположить, что все, что находится под единицами1e+5
(100000
) от корня / источника сцены, безопасно для работы.Но! Поскольку...
... тогда, вероятно, будет хорошей идеей повторно получить root намного раньше / чаще, чем отметка в 100000 единиц. Например, приведенный мной пример видео, кажется, делает это каждые 1000 единиц или около того.
источник
Оба варианта работают.
Но если вы хотите, чтобы бесконечный бегун был действительно бесконечным, вам придется держать игрока неподвижным и перемещать мир. В противном случае вы в конечном итоге достигнете пределов переменных, которые вы используете для хранения X-позиции. Целое число в конечном итоге переполняется, а переменная с плавающей запятой становится все менее точной, что через некоторое время делает игровой процесс затруднительным. Но вы можете избежать этой проблемы, используя достаточно большой тип, чтобы никто не столкнулся с этими проблемами в течение промежутка времени, который можно было бы воспроизвести за один сеанс (когда игрок перемещается со скоростью 1000 пикселей в секунду, 32-битное целое число переполняется через 49 дней).
Так что делайте то, что кажется вам концептуально более интуитивным.
источник
Основываясь на ответе XenoRo , вместо метода повторного укоренения, который они описывают, можно сделать следующее:
Создайте круговой буфер из сгенерированных частей вашей бесконечной карты, по которому ваш персонаж перемещается с позицией, обновляемой по арифметике по модулю (так что вы просто бегаете вокруг кругового буфера). Начните заменять части вашего буфера, как только ваш персонаж покинет кусок. Уравнение обновления игроков будет примерно таким:
player.position = (player.position + player.velocity) % worldBuffer.width;
Вот наглядный пример того, о чем я говорю:
Вот пример того, что происходит с упаковкой в конце.
С этим методом вы никогда не столкнетесь с ошибками точности, но вам может потребоваться создать очень большой буфер, если вы собираетесь делать это в 3D с очень большим расстоянием обзора (так как вам все равно нужно будет видеть впереди себя ). Если это беспорядочная птица, ваш размер фрагмента будет, вероятно, только настолько большим, насколько это необходимо для размещения одной сцены на одном экране, и ваш буфер может быть очень маленьким.
Обратите внимание , что вы будете начать , чтобы получить результаты , повторяя с ЛЮБЫМ PRNG, и максимальное количество не повторяющихся последовательностей PRNG поколения , как правило , меньше , чем длина мощна (2, число бит , используемой внутри), с merzenne TwisteR это не большая часть проблемы, так как он использует 2.5k внутреннего состояния, но если вы используете крошечный вариант, у вас есть 2 ^ 127-1 макс. итераций перед повторением (или хуже), однако это все еще астрономически большое число . Вы можете исправить проблемы повторяющихся периодов, даже если ваш PRNG имеет короткий период с помощью хороших лавинных функций смешивания для затравки (поскольку вы добавляете больше состояний неявно) несколько раз.
источник
Как уже было сказано и принято, это действительно зависит от объема и стиля вашей игры, но поскольку об этом не упоминалось: FlappyBird перемещает препятствие по экрану, а не по игроку по всему миру.
Спавнер создает объекты вне экрана с фиксированной скоростью в
Vector2.left
направлении.источник