Mit maximal 30 Objekten sollten Sie nicht viel Optimierung benötigen, außer dass Sie dieselben zwei Paare nicht mehr als einmal pro Frame gegeneinander prüfen. Was das folgende Codebeispiel abdeckt. Wenn Sie jedoch an verschiedenen Optimierungen interessiert sind, die eine Physik-Engine verwenden würde, lesen Sie den Rest dieses Beitrags weiter.
Was Sie benötigen, ist eine Implementierung zur räumlichen Partitionierung , z. B. ein Octree (für 3D-Spiele) oder ein Quadtree (für 2D-Spiele). Diese unterteilen die Welt in Unterabschnitte, und dann wird jeder Unterabschnitt im selben Herrenhaus weiter unterteilt, bis sie auf eine Mindestgröße unterteilt sind. Auf diese Weise können Sie sehr schnell überprüfen, welche anderen Objekte sich in derselben Region der Welt befinden wie andere, wodurch die Anzahl der Kollisionen begrenzt wird, gegen die Sie prüfen müssen.
Zusätzlich zur räumlichen Partitionierung würde ich empfehlen, für jedes Ihrer Physikobjekte einen AABB ( Axis-Aligned Bounding Box ) zu erstellen . Auf diese Weise können Sie den AABB eines Objekts mit einem anderen vergleichen. Dies ist viel schneller als eine detaillierte Prüfung pro Poly zwischen Objekten.
Dies kann für komplizierte oder große Physikobjekte noch einen Schritt weiter gehen, wobei Sie das Physiknetz selbst unterteilen können, wobei jeder Unterform ein eigenes AABB zugewiesen wird, gegen das Sie nur prüfen können, ob sich die AABBs zweier Objekte überlappen.
Die meisten Physik-Engines deaktivieren die aktive Physiksimulation auf Physikkörpern, sobald sie zur Ruhe kommen. Wenn ein Physikkörper deaktiviert ist, muss er nur in jedem Frame auf Kollision mit seinem AABB prüfen. Wenn etwas mit dem AABB kollidiert, wird er reaktiviert und führt eine detailliertere Kollisionsprüfung durch. Dies hält die Simulationszeiten niedrig.
Außerdem verwenden viele Physik-Engines "Simulationsinseln", auf denen eine Gruppe von Physikkörpern, die nahe beieinander liegen, zusammen gruppiert werden. Wenn alles auf der Simulationsinsel in Ruhe ist, wird die Simulationsinsel selbst deaktiviert. Der Vorteil der Simulationsinsel besteht darin, dass alle Körper in ihr aufhören können, nach Kollisionen zu suchen, sobald die Insel inaktiv ist. Die einzige Überprüfung jedes Frames besteht darin, festzustellen, ob etwas in den AABB der Insel gelangt ist. Erst wenn etwas in den AABB der Insel gelangt, muss jeder Körper auf der Insel nach Kollisionen suchen. Die Simulationsinsel wird auch reaktiviert, wenn sich ein Körper in ihr selbstständig wieder bewegt. Wenn sich ein Körper weit genug vom Zentrum der Gruppe entfernt, wird er von der Insel entfernt.
Am Ende bleibt dir so etwas (im Pseudocode):
// 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.
{
}
}
}
}
Ich würde auch empfehlen, nicht so viele Schleifen in solchen Schleifen zu haben. Das obige Beispiel war nur, damit Sie auf die Idee kamen. Ich würde es in mehrere Funktionen aufteilen, die Ihnen die gleiche Funktionalität bieten wie oben gezeigt.
Stellen Sie außerdem sicher, dass Sie den AABBNodes-Container während des Durchlaufens nicht ändern, da dies zu fehlenden Kollisionsprüfungen führen kann. Das mag nach gesundem Menschenverstand klingen, aber Sie wären überrascht, wie einfach es ist, wenn Dinge auf Kollisionen reagieren und Änderungen verursachen, die Sie nicht erwarten würden. Wenn beispielsweise eine Kollision dazu führte, dass eines der kollidierenden Objekte seine Position so weit änderte, dass es aus dem AABB des von Ihnen überprüften Octree-Knotens entfernt wurde, konnte dieser Container geändert werden. Um dies zu lösen, empfehle ich, eine Liste aller Kollisionsereignisse zu führen, die während der Überprüfungen auftreten. Nachdem alle Überprüfungen abgeschlossen sind, durchlaufen Sie die Liste und senden Sie alle Kollisionsereignisse aus.