Швидше 2D виявлення зіткнення


13

Нещодавно я працював над швидкодіючим 2d-шутером і зіткнувся з могутньою проблемою. Виявлення зіткнення. Звичайно, це працює, але це дуже повільно. Моя мета: мати багато ворогів на екрані і мати їх, щоб вони не торкалися один одного. Усі вороги переслідують сутність гравця. Більшість з них мають однакову швидкість, тому рано чи пізно всі вони в кінцевому підсумку займають однаковий простір, переслідуючи гравця. Це дійсно скасовує забавний фактор, оскільки для гравця схоже, що за вами переслідує тільки один ворог. Щоб не зайняти той самий простір, я додав виявлення зіткнення (дуже основне 2D-детектування, єдиний мені відомий метод).

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

Це чудово працює. Поки у мене є лише 200 ворожих утворень, тобто. Коли я наближаюся до 300-350 супротивників, частота кадрів починає сильно знижуватися. Спершу я подумав, що це погана передача, тому я зняв їхній розіграш. Це зовсім не допомогло, тому я зрозумів, що це метод оновлення. Єдиною важкою частиною їхнього методу оновлення є ця частина «ворог-петлі-через-кожного-ворога». Коли я наближаюся до 300 ворогів, гра робить ітерацію кроком 90000 (300x300). Мій мій ~

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

tl; dr? Як я можу визначити виявлення зіткнень між LOTS сутностей?

Швидке редагування: якщо це допоможе, я використовую C # XNA.


Мені цікаво, як у вас вийшло перейти в першу чергу до 90K. мінна дроселів на 20 К (я роблю повне детектування SAT MTV, хоча). Але я перебираю всіх ворогів - це єдине, що здається можливим. Що вам потрібно зробити, це перевірити, чи вони вже перевірені, тому що якщо ви так робите, ви говорите, то всі перевіряються з усіма двічі.
Delusional Logic


Є дуже гарна відповідь на питання, яке @MarkusvonBroady зв'язало.
Cypher

Відповіді:


11

Ви вже натрапили на свою проблему прямо по голові, у вас кожен орган перевіряє проти кожного іншого суб'єкта. Що вам захочеться, це якийсь тип системи «Рівень деталізації» (це, як правило, дуже простий графік сцени, ви просто використовуєте його для речей, крім рендеринга :)), де краще вибрати кандидатів зіткнення.

Я зазвичай роблю три колекції для такої системи. І коли ви говорите про кількість організацій, на які ви прагнете мати, можливо, вам навіть знадобиться отримати повний графік сцени для цього, оскільки дані відстеження (3 списки на одну особу із записом для кожної іншої особи) можуть швидко вийти контролю.

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

Наступний список - це ті, що знаходилися б у буферному діапазоні, який міг би переміститися в діапазон об'єкта із занадто великими зусиллями. Ми будемо називати цей діапазон X * 1.5 лише заради аргументу. Це нарізаний за часом список, в якому ви будете оновлювати лише декілька з них на кадр, але гарантуєте, що ви переглядаєте їх досить швидко, щоб не змінювати видимість роботи, яка працює безперебійно.

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

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

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

Сподіваюсь, це допомагає.


1
Це невиразна відповідь. І чи можемо ми прийняти пропустити деякі зіткнення ?? Набагато простіше, використовуйте структуру даних, яка зробить поділ поверхні для вас, як Quad Tree, про яке я говорю тут. Навіть Quad Tree потребує трохи тонкої настройки, щоб уникнути накладних витрат, тому я не можу уявити складність «рішення», про яке ви говорите. Основне правило програмування: просто використовуйте правильну структуру даних.
GameAlchemist

@VincentPiel Графік сцени не складніший за квадратичне дерево.
Cypher

@James: очевидно, це складніше. Якщо ви не проти зрозуміти повну швидкість QuadTree, ви можете отримати в мережі мережу QuadTree і змусити її працювати ідеально за пару годин. Немає питань на кшталт: що я поміщаю в перший список, другий, третій, як я вирішую внести суб'єкт до іншого списку ... і жодного зіткнення не пропустили. Навіщо користуватися велосипедом, коли можна мати автомобіль?
GameAlchemist

@VincentPiel Я думаю, ти мав на увазі @ твій коментар Cypher замість мене тут. Будь-яке дерево квадратиків - це лише тип сценічного графіка, і ви повинні пам’ятати, що ви працюєте зі швидкістю X кадрів в секунду. Якщо ви помічаєте пропущені зіткнення, тоді вам потрібно скорегувати пороги діапазону, щоб краще збалансувати речі. Моє рішення - це дуже простий підхід, щоб переконатися, що ви лише перевіряєте речі кожного кадру, які мають шанс зіткнутись, а потім робити фонові / обмежені оновлення для решти, щоб побачити, чи не відповідають вони ще на більш високий пріоритет.
Джеймс

6

Вам доведеться обробляти зіткнення з відсортованою структурою даних, щоб ви могли мати n * log (n) разів замість жахливих n ^ 2. І n * log (n) майже лінійний, як ви могли знати. Один (класичний) приклад - квадри, тут є досить простий і добре написаний підручник з графікою та кодом (Java):

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq: знайти QuadTrees досить просто на будь-якій мові. Тим не менш, ви повинні думати про правильну «деталізацію» для дерева, і чим більший розмір дерева, тим більше у нас сутностей, які не вміщуються всередині вузла.
Rq 2: оскільки ваш розподіл простору робиться лише для виявлення зіткнень, ви маєте ідеальну свободу ділити простір так, як вам подобається. Наприклад, я не поділяв би на чотири егальські частини, а скоріше використовував би барицентр суб'єктів поточного рівня як центр нового розриву. 1) алгоритм все ще n * log (n), 2) ви втрачаєте можливість "перебудувати" сцену з дерева - але вам все одно - і 3) у вас набагато більш врівноважене дерево, менше накладних витрат .
Rq3: Після того, як у вас є дерево, "зіткнення" між екраном і сутностями дає вам ... видимі сутності !! за час, більше схожий на log (n), то чому б і ні, якщо n великий? (найгірший випадок, очевидно, такий час для російського підходу.)


Так, квадратичне дерево - це справді лише такий тип графічного сцена. Я завжди припускаю, що люди, які перебувають тут, хочуть писати речі самі, а не користуватися чужою бібліотекою. У цьому випадку, чому зупинятися на квадровому дереві, просто знайти повну бібліотеку зіткнень.
Джеймс

0

бінарне дерево розділів простору, квадратура, octree (для 3D) - це можливі дерева, які ви можете генерувати (або підтримувати, якщо ви амбітні) під час кожного виклику оновлення для кожного об'єкта, до якого потрібно застосувати зіткнення.


3
Це більше підходить для коментаря. Розгляньте можливість додати більше до своєї відповіді.

0

Я дуже наївний, коли йдеться про квадратик або дерево окта. Але я думаю, що цей метод повинен робити:

Вам потрібно буде змінити структуру / клас гравця. Додайте масив / вектор покажчиків до іншої структури програвача.

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

Тепер лише перевіряйте зіткнення між гравцями у списку один одного.

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