2D платформи: навіщо робити фізику залежною від частоти кадрів?


12

"Super Meat Boy" - це складний платформер, який нещодавно вийшов на ПК, вимагаючи виняткового контролю та ідеальних піксельних стрибків. Код фізики в грі залежить від частоти кадрів, яка заблокована до 60 кадрів в секунду; це означає, що якщо ваш комп'ютер не зможе запустити гру на повній швидкості, фізика зійде з розуму, змусивши (крім усього іншого) вашого персонажа повільніше бігати і падати через землю. Крім того, якщо vsync вимкнено, гра працює надзвичайно швидко.

Чи могли б досвідчені з програмою 2D ігор пояснити, чому гра була закодована саме так? Невже фізичний цикл, що працює з постійною швидкістю, не стане кращим рішенням? (Насправді, я думаю, цикл фізики використовується для частин гри, оскільки деякі сутності продовжують нормально рухатися незалежно від частоти кадрів. З іншого боку, ваш персонаж працює так само [fps / 60].)

Мене турбує ця реалізація - це втрата абстракції між ігровим двигуном та графічною візуалізацією, яка залежить від конкретних системних речей, таких як монітор, відеокарта та процесор. Якщо з будь-якої причини ваш комп’ютер не може обробити vsync або не може запустити гру рівно 60 кадрів в секунду, вона зламається ефектно. Чому крок надання будь-яким чином повинен впливати на обчислення фізики? (Більшість ігор в даний час або сповільнюватимуть гру, або пропускають кадри.) З іншого боку, я розумію, що платформи старої школи на NES та SNES залежали від фіксованої частоти кадрів для більшої частини їхнього контролю та фізики. Чому це так, і чи можна було б створити формотворцю в цій вені, не маючи залежності від частоти кадрів? Чи обов'язково є втрата точності, якщо ви відокремлюєте відображення графіки від решти двигуна?

Дякую, і вибачте, якщо питання було заплутаним.


Дотичний до вашого питання. Ось чудова стаття, яка охоплює саме проблеми, які ви описуєте, та "правильний" спосіб обробки часових кроків та частоти кадрів. gafferongames.com/game-physics/fix-your-timestep
num1

Мене насправді насправді здивувало, що вони зроблять це так. Я думаю, що це має бути, оскільки він був побудований в основному для консолі, на якій можна покластись частоту кадрів. Розчарування!
Iain

Відповіді:


7

Чому?

Кілька причин, скористайтеся вибором: краще вони не знали. . Це швидше та простіше у виконанні. Вони були зосереджені більше на геймплейі і менше на крайніх випадках, які можуть не з’являтися в більшості випадків.

Ви зробили досить гарну роботу, пояснивши, чому ні. Я впевнений, що ви помітили, що існує маса тем, що висвітлюють цю тему . Я не впевнений, що ви знайдете задовільну відповідь, крім тих, які я перерахував.


"Вони не знали нічого кращого" описує, чому я застосував такий підхід із "Джеком дурнем". Але - я сильно покладався на виклик dt з останнього кадру з усією моєю логікою. Але - з координатами з плаваючою комою це може призвести до деяких дивних, важко повторюваних помилок
lochok

4

SMB спочатку була консольною грою, де можна припустити, що вона може працювати на 60 кадрів в секунду на всіх Xbox360 (ну, можливо, 50 для деяких гравців PAL). Припустимо, що фіксований часовий крок спрощує код неабияк.

Хоча легко масштабувати багато речей за змінним часовим кроком - "pos + = швидкість * timetep", це стає досить складно зробити це правильно, коли ви маєте справу з прискореннями, темпами зміни прискорення тощо.

Роз'єднання геймплея та рендерінга - це приємне рішення в теорії , але добре його реалізувати (при хорошій інтерполяції) досить складно, і все може легко заплутатися. Досить рідко цю техніку застосовують у реальних іграх (хоча деякі великі ігри роблять це, зокрема ігри RTS, але більше для синхронізації мережевих ігор).

Коли ви також проектуєте фіксовану роздільну здатність екрана, а також фіксовану частоту кадрів, ви можете зробити ще одну річ, щоб зробити прокрутку надзвичайно гладкою. Ви можете переконатися, що гра прокручується на цілу кількість пікселів на кадр, уникаючи «підпікселів», які ви можете отримати, прокручуючи дробову кількість пікселів на кадр.


1

Очевидним рішенням є 2 петлі, які працюють паралельно - візуалізація кожні 1/60 секунди та ігровий цикл кожні 1/60 секунди.

Але з моїм досвідом роботи у Flash (AS3, в якому я впевнений, що створений Super Meat Boy), планувальник не завжди дуже точний. Точність також сильно залежить від навколишнього середовища. У автономному флеш-плеєрі він може мати роздільну роздільну здатність. Але при запуску в деяких веб-браузерах точність стає частотою кадрів.

Таким чином, найближчим способом розв'язати логічний цикл візуалізації та ігор - це, щоб усі рухи були засновані на часі (і запускати кожен кадр залежно від того, скільки часу минуло з останнього кадру). Це може ввести деякі складніші математики (як, наприклад, гравітація застосовуватиметься постійно, а не додавати до об'єкта швидкість через задані інтервали). Оскільки гра може затриматись на секунду, і тоді ваш плеєр рухатиметься 200 пікселів за один крок, виявлення зіткнень та реагування на них можуть стати ще складнішими. Якщо програміст робив виявлення зіткнень на основі кадру (перевіряючи на зіткнення кожен часовий крок), їм також доведеться переходити на часове виявлення зіткнення. І якби вони хотіли, щоб це відчувало природність, вони повинні були б використовувати метод гравітації, описаний вище, який спричиняє рух об'єкта кривою (на відміну від лінії),


2
Оригінальний Meat Boy був флеш-грою. Super Meat Boy - гра на C ++.
Архагон

0

Я не думаю, що вже багато просити 2D-ігри для ПК на 60 кадрів в секунду. Навіть більшість 2D-ігор тепер прискорені апаратними засобами, тому особисто я б не переймався потребою в fps.

Справжнє питання полягає в тому, чому б ви не використовували піксельну основу, ігри повні читів і ярликів.

Якщо ви робите гру, засновану на фізиці (можливо, метання птахів?), Відповідь очевидна, але супер-маріо-клон? Рух на основі часу може бути небагато.


Їх не важко відтворити зі швидкістю 60 кадрів в секунду, але дисплеї зі стаціонарними частотами оновлення 50Гц, 70-85Гц та 120Гц все ще легко знайти.

0

Щоб уникнути дивної поведінки у фізиці 2d, яку вони використовують?

Чесно кажучи, я просто можу здогадатися. Спробую пояснити:

В основі гри основний цикл гри. Що в основному виглядає так:

while(gameRunning)
{
  updateGame(timestep);
  renderGame(timestep);
}

updateGame оновлює gameState: перевіряє введення гравця, застосовує введення гравця до ігрового світу та запускає фізичне моделювання тощо.

renderGame малює та анімує гру.

Це пари оновлює фізику до візуалізації. Якщо ви хочете роз'єднати його, вам знадобиться використовувати нитки та належним чином синхронізувати кожен доступ до даних візуалізації та нитку gameUpdate до загальних даних, наприклад позицію гравця. Це можна зробити.

Ще одна проблема може полягати в тому, що для фізичного моделювання потрібен постійний крок часу, щоб стабільно працювати. Це залежить від того, як супермітбой обчислює рух (Знову ми можемо просто здогадатися, як вони це зробили;)).

Наївним був би такий підхід (який я використовую у своїй грі * зітхання *):

position=position+speed*timestep;
speed=speed+acceleration*timestep;

Це називається інтеграція Ейлера і, як правило, вважається поганою ідеєю. Якщо часовий крок не є постійним помилками обчислення, це зробить моделювання менш стабільним. Об'єкт може рухатися з надмірною швидкістю або не всім або літати через стіни від екрану. Навіть якщо часовий крок постійний, інтеграція Euler викликає незначні помилки обчислення. Краще використовувати інший метод інтеграції, як RK4, або використовувати двигун фізики.

Крім цього, можуть бути проблеми з виявленням зіткнення, якщо часовий крок стає занадто великим. Оскільки зіткнення не перевіряються між двома ігровими оновленнями, об’єкти можуть пройти через перешкоди.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.