Наприклад, знаменита гра Flappy Bird, або все, що справді подібне, - гравець (у цьому випадку птах або камера, що б вам не було зручніше) рухається вперед або весь світ рухається назад (птах змінює лише положення Y і має постійне положення X)?
Наприклад, знаменита гра Flappy Bird, або все, що справді подібне, - гравець (у цьому випадку птах або камера, що б вам не було зручніше) рухається вперед або весь світ рухається назад (птах змінює лише положення Y і має постійне положення X)?
Відповіді:
Я трохи не погоджуюся з відповіддю Філіпа ; або хоча б з тим, як він це представив. Створюється враження, що переміщення світу навколо гравця може бути кращою ідеєю; коли це зовсім навпаки. Тож ось моя власна відповідь ...
Обидва варіанти можуть працювати, але взагалі погана ідея "перевернути фізику", переміщаючи світ навколо гравця, а не гравця по всьому світу.
У світі зазвичай буде багато об’єктів; багато, якщо не більшість, статичні або сплячі. У гравця буде один або порівняно небагато предметів. Переміщати весь світ навколо гравця, означає пересувати все на сцені, крім гравця. Статичні об'єкти, сплячі динамічні об'єкти, активні динамічні об'єкти, джерела світла, джерела звуку тощо; все треба перемістити.
Це (очевидно) значно дорожче, ніж переміщати лише те, що насправді рухається (гравець, а може, ще кілька речей).
Переміщення світу навколо гравця робить світ (і все в ньому) точкою, коли речі найбільш активно відбуваються. Будь-яка помилка чи зміна в системі означає, що потенційно все змінюється. Це не гарний спосіб робити речі; ви хочете, щоб помилки / зміни були максимально ізольованими, щоб не виникати несподіваних форм поведінки, де ви не внесли зміни.
Існує також багато інших проблем з таким підходом. Наприклад, це порушує багато припущень щодо того, як все має працювати в двигуні. RigidBody
Наприклад, ви не зможете використовувати динаміку ні для чого, крім гравця; як об'єкт із доданим RigidBody
не встановленим кінематичним поводом буде несподівано під час встановлення позиції / обертання / масштабу (що ви робите для кожного кадру, для кожного об'єкта в сцені, крім гравця 😨)
Ну ... так і ні . Як згадується у відповіді Філіпа, у нескінченному типі гри (або будь-якій грі з великою безшовною досліджуваною площею) занадто далеко від походження, врешті-решт, введеться помітні FPPE ( помилки з точністю з плаваючою точкою ), а далі, врешті-решт, переповнюють числовий тип, або спричиняючи крах вашої гри, або, в основному, роблять дим тріщин у світі гри ... На стероїди! 😵 (тому що до цього моменту FPPE змусили б гру вже бути "нормальною" тріщиною)
Не роби і того, і іншого! Ви повинні тримати світ статичним і рухати гравця навколо нього. Але «перезавантажте» і гравця, і світ, коли гравець починає надто далеко від кореня (позиції [0, 0, 0]
) сцени.
Якщо ви збережете відносну позицію речей (гравця до навколишнього світу) і виконайте цей процес в одному оновленні кадру, (фактичний) гравець навіть не помітить!
Для цього у вас є два основні варіанти:
Ось приклад цього процесу в дії
Якщо ви подивитесь на вихідний код Unity, вони використовують 1e-5
( 0.00001
) як основу для розгляду двох значень з плаваючою комою "рівних", усередині Vector2
та Vector3
(типів даних, що відповідають за позиції об'єктів, [ейлер-] обертання та масштаби). Оскільки втрата точності з плаваючою комою відбувається обома способами від нуля, можна припустити, що все, що знаходиться під 1e+5
( 100000
) одиницями, розташованими від кореня / джерела сцени, безпечно працювати.
Але! Оскільки ...
... тоді, мабуть, є хорошою ідеєю відновити корінь набагато раніше / частіше, ніж 100000 одиниць. Приклад відео, яке я надав, здається, робить це кожні 1000 одиниць або близько того, наприклад.
Обидва варіанти працюють.
Але якщо ви хочете, щоб нескінченний бігун був справді нескінченним, вам доведеться тримати гравця нерухомим та рухатись по світу. Інакше ви врешті-решт потрапите на межі змінних, які використовуєте для зберігання X-позиції. Ціле число з часом переповниться, і змінна з плаваючою точкою стане все менш точною, що зробить геймплей глюкізним через деякий час. Але ви можете уникнути цієї проблеми, використовуючи досить великий тип, щоб ніхто не стикався з цими проблемами протягом періоду часу, який можна було б відтворити за один сеанс (коли гравець рухається 1000 пікселів в секунду, 32-бітове ціле число переповниться через 49 днів).
Тож робіть все, що вам здається концептуально більш інтуїтивним.
Створюючи відповідь XenoRo , замість описаного ними методу повторного вкорінення можна зробити наступне:
Створіть круговий буфер частин вашої генерованої нескінченної карти, який ваш персонаж переміщається з положенням, оновленим арифметикою за модулем (так що ви просто біжите навколо кругового буфера). Почніть замінювати частини буфера, як тільки ваш персонаж покидає шматок. Рівняння оновлення гравців буде приблизно таким:
player.position = (player.position + player.velocity) % worldBuffer.width;
ось піктографічний приклад того, про що я говорю:
Ось приклад того, що відбувається при обгортанні в кінці.
За допомогою цього методу ви ніколи не зіткнетеся з помилками точності, але вам може знадобитися зробити дуже великий буфер, якщо ви збираєтесь робити це в 3d з дуже далеким оглядом (так як ви все ще повинні мати можливість бачити попереду себе ). Якщо у його крихкого птаха розмір вашої шматки, ймовірно, буде лише настільки великим, як потрібно для проведення однієї сцени для одного екрану, і ваш буфер може бути дуже крихітним.
Зауважте, що ви почнете отримувати повторювані результати з будь-якого PRng, а максимальна кількість повторюваних послідовностей покоління PRNG, як правило, менша за довжину пороху (2, кількість бітів, які використовуються всередині), при мерзенному твістері це не так більша частина проблеми, оскільки вона використовує 2,5 тис. внутрішнього стану, але якщо ви використовуєте крихітний варіант, у вас є 2 ^ 127-1 макс. ітерації перед повторним (або гірше), проте це все-таки астрономічно велика кількість . Ви можете виправити неповторні проблеми періоду, навіть якщо ваш PRNG має короткий період за допомогою хороших функцій перемішування лавини для насіння (оскільки ви додаєте більше стану непрямо) кілька разів.
Як вже було запропоновано та прийнято, це дійсно залежить від сфери та стилю вашої гри, але оскільки про неї не було сказано: FlappyBird пересуває перешкоду по екрану, а не гравця по всьому світу.
Нереститель створює екземпляри об'єктів із екрану з фіксованою швидкістю у Vector2.left
напрямку.