Маючи лише 30 об'єктів максимум, вам не потрібно мати великої оптимізації, крім того, щоб не перевіряти однакові дві пари один проти одного більше одного разу на кадр. Який наведений нижче зразок коду буде охоплювати. Але якщо вам цікаві різні оптимізації, які використовував би фізичний двигун, продовжуйте читати решту цього посту.
Вам знадобиться реалізація просторового розподілу , наприклад, Octree (для 3D-ігор) або Quadtree (для 2D-ігор). Вони поділяють світ на підрозділи, а потім кожний підрозділ ділиться далі в одній садибі, поки вони не поділяться на мінімальний розмір. Це дозволяє дуже швидко перевірити, які ще об’єкти знаходяться в тому ж регіоні світу, що й інший, що обмежує кількість зіткнень, з якими ви повинні перевірити.
На додаток до просторового розподілу я рекомендую створити AABB ( вікно, орієнтоване по осі ) для кожного з ваших фізичних об'єктів. Це дозволяє перевірити AABB одного об'єкта проти іншого, що набагато швидше, ніж детальна перевірка полі-полі між між об'єктами.
Це можна зробити ще на крок далі для складних або великих об’єктів фізики, де ви можете розділити саму фізичну сітку, надаючи кожній підформі свій власний AABB, на який ви можете перевірити, лише якщо два AABB об'єкта перекриваються.
Більшість двигунів фізики деактивує активне фізичне моделювання на фізичних тілах, як тільки вони відпочити. Коли фізичне тіло вимкнене, йому потрібно лише перевірити на зіткнення з його AABB кожен кадр, і якщо щось зіткнеться з AABB, то воно тоді повторно активується і зробить більш детальну перевірку зіткнення. Це зменшує час моделювання вниз.
Крім того, багато фізичних двигунів використовують "острівці моделювання", де група фізичних тіл, які знаходяться близько один до одного, об'єднуються. Якщо все на острові імітації знаходиться в спокої, то сам острів моделювання діє. Перевага імітаційного острова полягає в тому, що всі тіла, що знаходяться всередині нього, можуть припинити перевірку на зіткнення, коли острів неактивний, і єдина перевірка кожного кадру полягає у тому, щоб побачити, чи щось увійшло в AABB острова. Тільки після того, як щось ввійде в AABB острова, кожному з органів острова потрібно перевірити на зіткнення. Острів моделювання також знову активізується, якщо будь-яке тіло всередині нього знову почне рухатися самостійно. Якщо тіло рухається досить далеко від центру групи, воно видаляється з острова.
Зрештою, вам залишається щось подібне (у псевдокоді):
// Go through each leaf node in the octree. This could be more efficient
// by keeping a list of leaf nodes with objects in it.
for ( node in octreeLeafNodes )
{
// We only need to check for collision if more than one object
// or island is in the bounds of this octree node.
if ( node.numAABBsInBounds > 1)
{
for ( int i = 0; i < AABBNodes.size(); ++i )
{
// Using i+1 here allows us to skip duplicate checks between AABBS
// e.g (If there are 5 bodies, and i = 0, we only check i against
// indexes 1,2,3,4. Once i = 1, we only check i against indexes
// 2,3,4)
for ( int j = i + 1; j < AABBNodes.size(); ++j )
{
if ( AABBOverlaps( AABBNodes[i], AABBNodes[j] ) )
{
// If the AABB we checked against was a simulation island
// then we now check against the nodes in the simulation island
// Once you find overlaps between two actual object AABBs
// you can now check sub-nodes with each object, if you went
// that far in optimizing physics meshes.
{
}
}
}
}
Я також рекомендую не мати стільки циклів у циклах, як цей, вищевказаний зразок був саме таким, що ви отримали ідею, я би розбив її на кілька функцій, які надають вам таку ж функціональність, як щось на зразок того, що показано вище.
Також переконайтеся, що не змінюйте контейнер AABBNodes під час циклічного перегляду через нього, оскільки це може означати пропущені перевірки зіткнення. Це може здатися здоровим глуздом, але ви здивуєтеся, наскільки легко речі, що реагують на зіткнення, спричиняють зміни, яких ви не очікували. Наприклад, якщо зіткнення призвело до того, що один із об’єктів, що стикаються, змінив позицію достатньо, щоб видалити їх з AABB вузла Octree, який ви перевіряли, то це може змінити цей контейнер. Для вирішення цього питання я рекомендую зберігати список усіх зіткнень, що трапляються під час перевірок, а потім після того, як всі перевірки будуть завершені, проведіть список і надсилайте будь-які події зіткнення.