Існує велика різниця між двигуном зіткнення та двигуном фізики. Вони не роблять те саме, хоча двигун фізики, як правило, покладається на двигун зіткнення.
Потім двигун зіткнення розбивається на дві частини: виявлення зіткнення та реакцію на зіткнення. Останній, як правило, є частиною фізичного двигуна. Ось чому двигуни зіткнення і фізичні двигуни зазвичай згортаються в одну бібліотеку.
Виявлення зіткнення буває двох форм, дискретної та безперервної. Удосконалені двигуни підтримують і те, і інше, оскільки вони мають різні властивості. Взагалі, безперервне виявлення зіткнень дуже дороге і застосовується лише там, де воно справді потрібно. Більшість зіткнень та фізики вирішуються за допомогою дискретних методів. У дискретних методах об'єкти в кінцевому підсумку проникають один у одного, а фізичний двигун працює над тим, щоб розсунути їх. Тож двигун насправді не зупиняє гравця частково ходити по стіні чи підлозі, він просто фіксує його після виявлення того, що гравець частково знаходиться в стіні / підлозі. Я збираюся зосередитись на дискретному виявленні зіткнень, оскільки саме це я маю найбільший досвід впровадження з нуля.
Виявлення зіткнення
Виявлення зіткнення відносно легко. Кожен об’єкт має перетворення та форму (можливо, декілька фігур). Наївні підходи повинні змусити двигун зіткнення зробити цикл O (n ^ 2) через всю об'єктну пару і випробувати, якщо між парами накладеться перекриття. У розумніших підходах є кілька просторових структур даних (наприклад, для статичних та динамічних об'єктів), обмежуюча форма для кожного об'єкта та багаточастинні опуклі підформи для кожного об'єкта.
Структури просторових даних включають такі речі, як KD-Дерева, динамічні дерева AABB, Octrees / Quadtrees, Binary Space Partitioning дерева тощо. У кожного є свої переваги та недоліки, тому деякі двигуни вищого класу використовують більше одного. Наприклад, динамічні дерева AABB дійсно дуже швидкі і хороші для обробки безлічі рухомих об'єктів, тоді як KD-дерево може бути більш придатним для геометричної статичної рівня, з якою стикаються об'єкти. Є й інші варіанти.
Широка фаза використовує структури просторових даних та абстрактний обмежуючий обсяг для кожного об'єкта. Обмежуючий об'єм - це проста форма, яка охоплює весь об'єкт, як правило, з метою закріпити його максимально "щільно", залишаючись дешевим, щоб зробити тести зіткнення. Найпоширеніші обмежувальні форми - це осеві вирівнювання, орієнтовані на осі, об'ємно-орієнтовані обмежувальні коробки, сфери та капсули. AABBs, як правило, вважаються найшвидшими та найпростішими (сфери в деяких випадках простіші та швидші, але для багатьох таких просторових структур даних все-таки знадобиться перетворення сфери в AABB), але вони також мають тенденцію досить погано вміщувати багато об'єктів. Капсули популярні в 3D-двигунах для управління зіткненнями на рівні персонажів. Деякі двигуни будуть використовувати дві обмежуючі форми,
Остання фаза виявлення зіткнення - це виявлення, де саме перетинається геометрія. Зазвичай це передбачає використання сітки (або багатокутника в 2D), хоча не завжди. Мета цього етапу - з’ясувати, чи справді об'єкти справді стикаються, чи потрібен тонкий рівень деталізації (скажімо, зіткнення кулі в стрільці, де ви хочете ігнорувати постріли, які ледь не пропускають), і також з’ясувати, де саме стикаються об’єкти, що впливатиме на те, як реагують об’єкти. Наприклад, якщо ящик сидить на краю столу, двигун повинен знати, в яких моментах стіл притискається до коробки; залежно від того, наскільки далеко висить ящик, коробка може почати нахилятися і опадати.
Контактний генератор
Використовувані тут алгоритми включають популярні алгоритми доопрацювання порталу GJK та Minkowski, а також тест роздільної осі. Оскільки популярні алгоритми, як правило, працюють лише для опуклих фігур, необхідно розбити багато складних об'єктів на опуклі суб'єкти та зробити тести зіткнення для кожного окремо. Це одна з причин, чому спрощені сітки часто використовуються для зіткнення, а також скорочення часу обробки для використання меншої кількості трикутників.
Деякі з цих алгоритмів не лише говорять вам про те, що об'єкти зіткнулися точно, але і де вони зіткнулися - наскільки далеко вони проникають один в одного та які "точки контакту". Для отримання цієї інформації для деяких алгоритмів потрібні додаткові кроки, такі як відсікання багатокутника.
Фізична реакція
У цей момент було виявлено контакт, і фізична система має достатньо інформації для обробки контакту. Обробка фізики може стати дуже складною. Простіші алгоритми працюють для деяких ігор, але навіть щось таке ж начебто прямолінійне, як збереження стопки ящиків стабільним виявляється досить складно і вимагає багато роботи та не очевидних хак.
На самому базовому рівні фізичний двигун зробить щось подібне: він забере об'єкти, що стикаються, та їх контактний колектор і обчислить нові позиції, необхідні для розділення зіштовхуваних об'єктів. Він перемістить об’єкти на ці нові позиції. Він також обчислить зміну швидкості, що виникає в результаті цього натискання, у поєднанні зі значеннями реституції (бадьорості) та тертя. Двигун фізики також застосує будь-які інші сили, що діють на об'єкти, наприклад, гравітація, для обчислення нових швидкостей об'єктів, а потім (наступний кадр) їх нових позицій.
Більш просунута фізична реакція швидко ускладнюється. Підхід, описаний вище, руйнується у багатьох ситуаціях, включаючи один об'єкт, що сидить поверх двох інших. Зв'язок з кожною парою сам по собі викличе «тремтіння», і об’єкти будуть багато підстрибувати. Найбільш основний прийом - це зробити ряд ітерацій корекції швидкості над парами об'єктів, що стикаються. Наприклад, з коробкою "А", що сидить поверх двох інших коробок "В" і "С", зіткнення AB спочатку буде оброблятися, внаслідок чого коробка A буде нахилятися далі в коробку C. Потім відбувається зіткнення змінного струму, ввечері вийміть коробки трохи, але потягнувши A вниз і B. Потім робиться ще одна ітерація, тому помилка AB, викликана корекцією змінного струму, трохи усувається, створюючи трохи більше помилок у відповіді змінного струму. Що обробляється при повторній обробці змінного струму. Кількість виконаних ітерацій не визначена, і немає сенсу, коли він стає «ідеальним», а навпаки, будь-яка кількість ітерацій не припиняє давати значущих результатів. 10 ітерацій є типовою першою спробою, але потрібно налаштувати, щоб визначити найкраще число для певного двигуна та певної потреби гри.
Зверніться до кешування
Є й інші хитрощі, які виявляються дуже зручними (більш-менш потрібними) при роботі з багатьма видами ігор. Контактне кешування - одна з найбільш корисних. За допомогою кеша контактів кожен набір об'єктів, що стикаються, зберігається в таблиці пошуку. Кожен кадр, коли виявлено зіткнення, цей кеш запитується, щоб перевірити, чи об'єкти раніше контактували. Якщо об'єкти раніше не контактували, то може бути створена подія "нового зіткнення". Якщо об'єкти раніше контактували, інформацію можна використовувати для забезпечення більш стійкої реакції. Будь-які записи в кеш-контактах, які не були оновлені в кадрі, вказують на два об'єкти, які розділилися, і подія "об'єкт, що розділяє", може бути створена. Логіка гри часто використовує ці події.
Логіка гри також може реагувати на нові події зіткнення і позначати їх як ігноровані. Це справді корисно для впроваджених деяких функцій, поширених на платформах, як-от платформи, через які ви можете стрибати, але стояти далі. Наївні реалізації можуть просто ігнорувати зіткнення, які мають зіткнення платформи вниз -> нормальне зіткнення (вказує на те, що голова гравця потрапила в нижню частину платформи), але без контактного кешування це зламається, якщо голова гравця вискакує через платформу, і тоді він починає падати. У цей момент нормальний контакт може в кінцевому підсумку вказувати вгору, внаслідок чого гравець вискакує через платформу, коли той не повинен. За допомогою кешування контактів двигун може надійно дивитись на початкове зіткнення нормально і ігнорувати всі подальші контактні події, поки платформа та плеєр знову не розлучаться.
Сплячий
Ще одна дуже корисна методика - позначати об'єкти як "сплячі", якщо вони не взаємодіють з ними. Сплячі об’єкти не отримують оновлень фізики, не стикаються з іншими спальними об’єктами, а в основному просто сидять там застиглі в часі, поки інший неспальний об’єкт не зіткнеться з ними.
Вплив полягає в тому, що всі пари об'єктів, що стикаються, які просто сидять там, не роблячи нічого, не займають часу на обробку. Крім того, оскільки немає постійної кількості крихітних корекцій фізики, стеки будуть стабільними.
Об'єкт є кандидатом для сну, коли він мав майже нульову швидкість більше, ніж один кадр. Зауважте, що епсилон, який ви використовуєте для тестування цієї майже нульової швидкості, ймовірно, буде трохи вище, ніж звичайний епсилон порівняння з плаваючою точкою, тому що ви повинні очікувати деякого тремтіння зі складеними об'єктами, і ви хочете, щоб цілі стеки об'єктів заснули, якщо вони ' залишатися "досить близько" до стабільного. Поріг, звичайно, вимагатиме налаштування та експериментів.
Обмеження
Останній головний біт багатьох фізичних двигунів - це вирішення обмежень. Мета такої системи - полегшити реалізацію таких речей, як пружини, двигуни, вісь колеса, імітовані м'які тіла, тканина, мотузки та ланцюги, а іноді навіть рідина (хоча рідина часто реалізується як зовсім інша система).
Навіть основи вирішення обмежень можуть бути дуже інтенсивними з математики і виходять за рамки мого досвіду в цій темі. Рекомендую ознайомитись із чудовою серією статей з фізики Ренді Гаула для більш поглибленого пояснення теми.