Avec seulement 30 objets maximum, vous ne devriez pas avoir besoin de beaucoup d'optimisation, sinon de ne pas comparer les deux mêmes paires plus d'une fois par image. Ce que l'exemple de code ci-dessous couvrira. Mais si vous êtes intéressé par différentes optimisations qu'un moteur physique utiliserait, continuez à lire le reste de ce post.
Ce dont vous aurez besoin est une implémentation de partitionnement spatial , comme un Octree (pour les jeux 3D) ou Quadtree (pour les jeux 2D). Celles-ci partitionnent le monde en sous-sections, puis chaque sous-section est partitionnée davantage dans le même manoir, jusqu'à ce qu'elles se soient subdivisées en une taille minimale. Cela vous permet de vérifier très rapidement quels autres objets se trouvent dans la même région du monde qu'un autre, ce qui limite le nombre de collisions que vous devez vérifier.
En plus du partitionnement spatial, je recommanderais de créer un AABB ( boîte de délimitation alignée sur l'axe ) pour chacun de vos objets physiques. Cela vous permet de comparer l'AABB d'un objet par rapport à un autre, ce qui est beaucoup plus rapide qu'une vérification détaillée par poly entre objets.
Cela peut être encore plus loin pour les objets physiques complexes ou volumineux, où vous pouvez subdiviser le maillage physique lui-même, en donnant à chaque sous-forme son propre AABB que vous pouvez vérifier uniquement si les AABB de deux objets se chevauchent.
La plupart des moteurs physiques désactiveront la simulation physique active sur les corps physiques une fois qu'ils se seront arrêtés. Lorsqu'un corps physique est désactivé, il n'a qu'à vérifier la collision avec son AABB à chaque trame, et si quelque chose entre en collision avec l'AABB, il le réactivera et fera un contrôle de collision plus granulaire. Cela réduit les temps de simulation.
En outre, de nombreux moteurs physiques utilisent des «îlots de simulation», c'est-à-dire un groupe de corps physiques proches les uns des autres. Si tout dans l'îlot de simulation est au repos, l'îlot de simulation se désactive. L'avantage de l'îlot de simulation est que tous les corps à l'intérieur peuvent cesser de vérifier les collisions une fois que l'îlot est inactif, et la seule vérification de chaque trame est de voir si quelque chose est entré dans l'AABB de l'îlot. Ce n'est qu'une fois que quelque chose entre dans l'AABB de l'île que chacun des corps de l'île devra vérifier les collisions. L'îlot de simulation se réactive également si un corps à l'intérieur de celui-ci recommence à se déplacer tout seul. Si un corps s'éloigne suffisamment du centre du groupe, il est retiré de l'île.
À la fin, vous vous retrouvez avec quelque chose comme ça (en pseudo-code):
// 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.
{
}
}
}
}
Je recommanderais également de ne pas avoir autant de boucles dans des boucles comme celle-ci, l'exemple ci-dessus était juste pour que vous ayez l'idée, je le décomposerais en plusieurs fonctions qui vous donnent la même fonctionnalité que quelque chose comme ce qui est montré ci-dessus.
Assurez-vous également de ne pas modifier le conteneur AABBNodes lors de sa boucle, car cela pourrait signifier des contrôles de collision manqués. Cela peut sembler du bon sens, mais vous seriez surpris de la facilité avec laquelle les choses réagissant aux collisions provoquent des changements que vous ne prévoyez pas. Par exemple, si une collision faisait que l'un des objets entrant en collision changeait suffisamment de position pour les supprimer de l'AABB du nœud Octree que vous vérifiiez, cela pourrait altérer ce conteneur. Pour résoudre ce problème, je recommande de conserver une liste de tous les événements de collision qui se produisent pendant les vérifications, puis une fois toutes les vérifications terminées, parcourez la liste et envoyez tous les événements de collision.