Questa domanda è una domanda di "follow-up" della mia precedente, riguardante il rilevamento e la risoluzione delle collisioni, che puoi trovare qui .
Se non vuoi leggere la domanda precedente, ecco una breve descrizione di come funziona il mio motore fisico:
Ogni entità fisica è archiviata in una classe chiamata SSSPBody.
Sono supportati solo AABB.
Ogni SSSPBody è archiviato in una classe chiamata SSSPWorld, che aggiorna ogni corpo e gestisce la gravità.
Ogni frame, SSSPWorld aggiorna ogni corpo.
Ogni corpo aggiornato cerca corpi vicini in un hash spaziale, controlla se devono rilevare collisioni con loro. Se sì, invocano un evento di "collisione" e controllano se devono risolvere le collisioni con loro. Se sì, calcolano il vettore di penetrazione e la sovrapposizione direzionale, quindi cambiano posizione per risolvere la penetrazione.
Quando un corpo si scontra con un altro, trasferisce la sua velocità sull'altro semplicemente impostando la velocità del corpo sulla propria.
La velocità di un corpo è impostata su 0 quando non ha cambiato posizione rispetto all'ultimo fotogramma. Se si scontra anche con un corpo in movimento (come un ascensore o una piattaforma mobile), calcola la differenza di movimento dell'ascensore per vedere se il corpo non si è mosso dalla sua ultima posizione.
Inoltre, un corpo invoca un evento "schiacciato" quando tutti i suoi angoli AABB si sovrappongono a qualcosa in una cornice.
Questo è il codice sorgente COMPLETO del mio gioco. È diviso in tre progetti. SFMLStart è una semplice libreria che gestisce input, disegno e aggiornamento di entità. SFMLStartPhysics è il più importante, dove si trovano le classi SSSPBody e SSSPWorld. PlatformerPhysicsTest è il progetto di gioco, contenente tutta la logica del gioco.
E questo è il metodo "update" nella classe SSSPBody, commentato e semplificato. Puoi dare un'occhiata solo a questo se non hai voglia di guardare l'intero progetto SFMLStartSimplePhysics. (E anche se lo fai, dovresti comunque dare un'occhiata a questo dato che è commentato.)
Il .gif mostra due problemi.
- Se i corpi sono posizionati in un ordine diverso, si verificano risultati diversi. Le casse a sinistra sono identiche alle casse a destra, disposte solo nell'ordine inverso (nell'editor).
- Entrambe le casse dovrebbero essere spinte verso la parte superiore dello schermo. Nella situazione a sinistra, non vengono azionate casse. A destra, solo uno di questi è. Entrambe le situazioni non sono intenzionali.
Primo problema: ordine di aggiornamento
Questo è abbastanza semplice da capire. Nella situazione a sinistra, la cassa più in alto viene aggiornata prima dell'altra. Anche se la cassa in basso "trasferisce" la velocità all'altra, deve attendere che il fotogramma successivo si sposti. Poiché non si è mosso, la velocità della cassa inferiore è impostata su 0.
Non ho idea di come risolvere questo problema. Preferirei che la soluzione non dipendesse dal "ordinamento" dell'elenco degli aggiornamenti, perché sento che sto facendo qualcosa di sbagliato nell'intero progetto del motore fisico.
In che modo i principali motori fisici (Box2D, Bullet, Chipmunk) gestiscono l'ordine di aggiornamento?
Secondo problema: una sola cassa viene spinta verso il soffitto
Non capisco ancora perché questo accada. Ciò che fa l'entità "molla" è impostare la velocità del corpo a -4000 e riposizionarla sulla parte superiore della molla stessa. Anche se disabilito il codice di riposizionamento, il problema si verifica comunque.
La mia idea è che quando la cassa inferiore si scontra con la cassa superiore, la sua velocità è impostata su 0. Non sono sicuro del perché ciò accada.
Nonostante la possibilità di sembrare qualcuno che si arrende al primo problema, ho pubblicato l'intero codice sorgente del progetto sopra. Non ho nulla per dimostrarlo, ma credetemi, ho cercato di risolverlo ma non riuscivo a trovare una soluzione e non ho alcuna esperienza precedente con la fisica e le collisioni. Ho cercato di risolvere questi due problemi per più di una settimana e ora sono disperato.
Non credo di poter trovare una soluzione da solo senza togliere molte funzionalità dal gioco (trasferimento della velocità e molle, per esempio).
Grazie mille per il tempo dedicato a leggere questa domanda e grazie ancora di più se provi persino a trovare una soluzione o un suggerimento.