Редагувати: коментар ОП скептично ставився до ефективності запропонованої негативної кругової перевірки для вдосконалення алгоритму, щоб перевірити, чи лежить довільна точка 2D у межах обертового та / або рухомого прямокутника. Трохи обертаючись моїм 2D ігровим механізмом (OpenGL / C ++), я доповнюю свою відповідь, надаючи орієнтир продуктивності мого алгоритму проти поточних алгоритмів (і варіацій перевірки ОП) в поточному прямокутнику.
Спочатку я запропонував залишити алгоритм на місці (як це майже оптимально), але спростити за допомогою простої логічної гри: (1) за допомогою попередньо обробленого кола навколо початкового прямокутника; (2) зробити перевірку відстані, і якщо точка лежить у межах даного кола; (3) використовувати ОП або інший прямий алгоритм (я рекомендую алгоритм isLeft, як це передбачено в іншій відповіді). Логіка моєї пропозиції полягає в тому, що перевірка того, чи знаходиться точка в колі, є значно ефективнішою, ніж гранична перевірка повернутого прямокутника чи будь-якого іншого багатокутника.
Мій початковий сценарій тесту на тест - запустити велику кількість точок, що з’являються і зникають (положення яких змінюється в кожному циклі гри) у обмеженому просторі, який заповниться приблизно 20 квадратами, що обертаються / рухаються. Для ілюстрації я опублікував відео ( посилання на youtube ). Зверніть увагу на параметри: кількість випадково з’являються крапок, число або прямокутники. Я буду орієнтуватись на такі параметри:
OFF : Прямий алгоритм, передбачений ОП, без негативної перевірки меж кола
ON : використання перероблених (граничних) кіл навколо прямокутників у якості першої перевірки виключення
ON + стек : створення меж кола під час виконання циклу в циклі стека
ON + Квадратне відстань : Використання квадратних відстаней як додаткової оптимізації, щоб уникнути використання більш дорогого алгоритму квадратного кореня (Pieter Geerkens).
Ось підсумок різних виконання різних алгоритмів, показуючи час, необхідний для перегляду циклу.
Вісь x показує підвищену складність, додаючи більше крапок (і тим самим сповільнюючи цикл). (Наприклад, при 1000 перевірки точок, що з'являються випадковим чином, у конфіденційному просторі з 20 прямокутниками, цикл повторюється і викликає алгоритм 20000 разів.) Вісь y показує час, який потрібно (мс), щоб пройти весь цикл, використовуючи високу роздільну здатність таймер продуктивності. Більше 20 мс було б проблематично для гідної гри, оскільки вона не скористалася б високою швидкістю кадрів в секунду, щоб інтерполювати гладку анімацію, і гра може виглядати таким чином "міцною" часом.
Результат 1 : Попередньо оброблений круговий зв'язаний алгоритм з швидкою негативною перевіркою в циклі покращує продуктивність на 1900% порівняно зі звичайним алгоритмом (5% від початкового часу циклу без перевірки). Результат відповідає приблизно пропорційному кількості ітерацій в циклі, тому не має значення, перевіряємо 10 або 10000 випадково з'являються точок. Таким чином, на цій ілюстрації можна безпечно збільшити кількість об'єктів до 10 к, не відчуваючи втрати продуктивності.
Результат 2 : Попереднім коментарем було запропоновано сказати, що алгоритм може бути швидшим, але об'єм пам'яті. Однак зауважте, що зберігання поплавця для попередньо обробленого розміру кола займає лише 4 байти. Це не повинно створювати реальних проблем, якщо ОП не планує одночасно запускати 100000+ об'єктів. Альтернативний і ефективний підхід в пам’яті полягає в тому, щоб обчислити максимальний розмір кола на стеку в циклі і випустити його за межі кожної ітерації і, таким чином, практично не використовувати пам'ять за деяку невідому ціну швидкості. Дійсно, результат показує, що цей підхід дійсно повільніше, ніж використання розміру попередньо обробленого кола, але він все ще показує значне поліпшення продуктивності приблизно на 1150% (тобто 8% від початкового часу обробки).
Результат 3 : Я додатково вдосконалюю алгоритм результату 1, використовуючи відстані в квадраті замість фактичних відстаней і, таким чином, приймаючи обчислювально дорогу операцію квадратного кореня. Це лише плавно підвищує продуктивність (2400%). (Примітка. Я також пробую хеш-таблиці для попередньо оброблених масивів для наближень квадратних коренів з аналогічним, але трохи гіршим результатом)
Результат 4 : я додатково перевіряю переміщення / стикання прямокутників навколо; однак це не змінює основних результатів (як очікувалося), оскільки логічна перевірка залишається по суті однаковою.
Результат 5 : Я змінюю кількість прямокутників і виявляю, що алгоритм стає ще більш ефективним, тим менш зайнятим є простір (не показаний у демонстрації). Результат також дещо очікуваний, оскільки зменшується ймовірність появи точки в межах невеликого простору між колом та межами об'єкта. З іншого боку, я намагаюся збільшити кількість прямокутників теж на 100 в межах одного обмеженого крихітного простору І динамічно змінювати їх за розмірами під час виконання в межах циклу (sin (ітератор)). Це як і раніше надзвичайно добре із збільшенням продуктивності на 570% (або на 15% від початкового часу циклу).
Результат 6 : Я тестую альтернативні алгоритми, запропоновані тут, і виявляю дуже незначну, але не суттєву різницю в продуктивності (2%). Цікавий і простіший алгоритм IsLeft працює дуже добре з підвищенням продуктивності на 17% (85% від початкового часу розрахунку), але ніде не досягає ефективності алгоритму швидкої негативної перевірки.
Моя суть - спершу розглянути мізерний дизайн та логіку гри, особливо коли йдеться про межі та події зіткнення. Поточний алгоритм ОП вже досить ефективний, і подальша оптимізація не є настільки важливою, як оптимізація самої основної концепції. Більше того, добре повідомити обсяг і мету гри, оскільки ефективність алгоритму критично залежить від них.
Я пропоную завжди намагатися орієнтувати будь-який складний алгоритм на етапі проектування гри, оскільки просто перегляд простого коду може не виявити правду про фактичну продуктивність роботи. Запропонований алгоритм може не бути тут навіть необхідним, якщо, наприклад, потрібно просто перевірити, чи знаходиться курсор миші у прямокутнику чи ні, або коли більшість об'єктів вже торкаються. Якщо більшість балів перевіряються в прямокутнику, алгоритм буде менш ефективним. (Однак тоді можна було б встановити межу "внутрішнього кола" як вторинну негативну перевірку.) Перевірка меж кола / сфери є дуже корисною для будь-якого пристойного виявлення зіткнення великої кількості об'єктів, які мають природний простір між ними .
Rec Points Iter OFF ON ON_Stack ON_SqrDist Ileft Algorithm (Wondra)
(ms) (ms) (ms) (ms) (ms) (ms)
20 10 200 0.29 0.02 0.04 0.02 0.17
20 100 2000 2.23 0.10 0.20 0.09 1.69
20 1000 20000 24.48 1.25 1.99 1.05 16.95
20 10000 200000 243.85 12.54 19.61 10.85 160.58