Con solo 30 oggetti al massimo, non dovresti aver bisogno di molta ottimizzazione se non quella di non controllare le stesse due coppie una contro l'altra più di una volta per fotogramma. Di cui verrà coperto l'esempio di codice riportato di seguito. Ma se sei interessante in diverse ottimizzazioni che un motore fisico userebbe, continua a leggere il resto di questo post.
Ciò di cui avrai bisogno è un'implementazione del partizionamento spaziale , come un Octree (per i giochi 3D) o Quadtree (per giochi 2D). Questi suddividono il mondo in sottosezioni, e quindi ogni sottosezione viene ulteriormente suddivisa nello stesso maniero, fino a quando non si suddividono in una dimensione minima. Ciò consente di verificare rapidamente quali altri oggetti si trovano nella stessa regione del mondo di un'altra, il che limita la quantità di collisioni che è necessario verificare.
Oltre al partizionamento spaziale, consiglierei di creare un AABB ( riquadro di selezione allineato agli assi ) per ciascuno dei tuoi oggetti di fisica. Ciò consente di controllare l'AABB di un oggetto rispetto a un altro, che è molto più veloce di un controllo dettagliato per poli tra oggetti.
Questo può essere fatto un ulteriore passo avanti per oggetti fisici complessi o di grandi dimensioni, in cui è possibile suddividere la mesh fisica stessa, dando ad ogni sottoforma il proprio AABB che è possibile verificare solo se due AABB di oggetti si sovrappongono.
La maggior parte dei motori di fisica disattiverà la simulazione di fisica attiva sui corpi fisici una volta che si fermeranno. Quando un corpo fisico è disattivato, deve solo controllare la collisione con il suo AABB per ogni fotogramma e se qualcosa si scontra con l'AABB, allora si riattiverà e farà un controllo di collisione più granulare. Ciò mantiene bassi i tempi di simulazione.
Inoltre, molti motori fisici usano le "isole di simulazione", dove un gruppo di corpi fisici vicini è raggruppato. Se tutto nell'isola di simulazione è a riposo, l'isola di simulazione stessa si disattiva. Il vantaggio dell'isola di simulazione è che tutti i corpi al suo interno possono smettere di controllare le collisioni una volta che l'isola è inattiva, e l'unico controllo di ogni fotogramma è vedere se qualcosa è entrato nella AABB dell'isola. Solo una volta che qualcosa entra nell'ABAB dell'isola, ciascuno dei corpi all'interno dell'isola dovrà controllare le collisioni. L'isola di simulazione si riattiva anche se un corpo al suo interno inizia a muoversi di nuovo da solo. Se un corpo si sposta abbastanza lontano dal centro del gruppo, viene rimosso dall'isola.
Alla fine ti rimane qualcosa di simile (in pseudo-codice):
// 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.
{
}
}
}
}
Consiglierei anche di non avere così tanti loop all'interno di loop come questo, l'esempio sopra è stato solo così hai avuto l'idea, lo spezzerei in più funzioni che ti danno la stessa funzionalità di qualcosa come quello mostrato sopra.
Inoltre, assicurarsi di non alterare il contenitore AABBNodes durante il ciclo, in quanto ciò potrebbe significare controlli di collisione persi. Può sembrare un senso comune, ma rimarrai sorpreso dalla facilità con cui le cose che reagiscono alle collisioni causano cambiamenti che non ti aspetti. Ad esempio, se una collisione ha causato una modifica della posizione di uno degli oggetti in collisione per rimuoverli dall'AABB del nodo Octree che si stava verificando, potrebbe alterare quel contenitore. Per risolvere questo problema, ti consiglio di tenere un elenco di tutti gli eventi di collisione che si verificano durante i controlli, quindi dopo aver completato tutti i controlli esegui l'elenco e invia tutti gli eventi di collisione.