Если максимум 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, который вы проверяли, он может изменить этот контейнер. Чтобы решить эту проблему, я рекомендую вести список всех событий столкновения, которые происходят во время проверок, а затем, после того как все проверки завершены, просмотрите список и отправьте все события столкновения.