Risolvere una collisione con forze


14

Nel mio motore di fisica 2D, posso rilevare le collisioni AABB vs AABB e risolverle trovando il vettore di penetrazione più breve e aggiungendolo alla posizione dell'AABB.

Fare questo "spinge" il primo AABB al di fuori del secondo AABB, ma non si occupa affatto dei cambiamenti di velocità / accelerazione.

Se aggiungo l'accelerazione di gravità alla mia simulazione, la velocità del primo AABB dinamico continua a crescere anche quando è appoggiata sul secondo AABB statico. Alla fine, la velocità diventerà troppo grande e la collisione non verrà rilevata (l'AABB dinamico cadrà attraverso quello statico).

Ho provato a impostare la velocità a zero dopo la risoluzione, ma ovviamente non ha funzionato bene e ho creato simulazioni non realistiche.

Ho letto online che la risoluzione delle collisioni lavorando manualmente sulla posizione o sulla velocità non è corretta. Ho provato a implementare le forze (la massa è un "hardcoded" 1 per ora):

void Body::applyForce(sf::Vector2f mForce) { acceleration += mForce; }

void Body::integrate(float mFrameTime)
{
    velocity += acceleration * mFrameTime;
    position += velocity * mFrameTime;

    acceleration = {0, 0};
}

Se applico il vettore di penetrazione più breve come forza durante la risoluzione della collisione, l'AABB dinamico verrà "espulso" da quello statico, ma la sua velocità non diminuirà mai in una simulazione senza gravità e continuerà a muoversi per sempre.

C'è un modo per applicare una forza "temporanea"? Una forza che si occupa di spingere il primo AABB fuori dal secondo AABB, poi si ferma quando l'AABB non si scontra più?

Tutto il codice sorgente disponibile qui: https://github.com/SuperV1234/SSVSCollision


1
Sono interessato a questo. Hai già trovato una soluzione?
TravisG,

@TravisG: non ancora, sfortunatamente. Aggiungerò una taglia domani se non avrò alcuna risposta.
Vittorio Romeo,

La forza non eguaglia l'accelerazione, prima di tutto. È necessaria la massa per calcolare l'accelerazione. Se stai modificando le posizioni per impedire ai due corpi di penetrare, dovresti usare anche la massa e spostare entrambi i corpi in base a esso. L'applicazione di una forza uguale al vettore di penetrazione non ha alcun merito. Box2D è basato sugli impulsi, funziona direttamente sulle velocità, potrebbe non essere "corretto", ma è abbastanza buono. Affrontare i cambiamenti di velocità in un motore basato sugli impulsi è molto semplice, quindi potresti specificare se desideri definitivamente una soluzione basata sulla forza o la soluzione basata sugli impulsi molto più semplice è abbastanza buona.
dreta,

Personalmente, suggerirei di prendere un libro sui motori della fisica, almeno leggere i primi capitoli sulla fisica newtoniana. I tuoi presupposti sono errati e cercare di rispondere a questa domanda significherebbe dover insegnarti le basi della fisica mentre provi a spiegare algoritmi di alto livello per risolvere le collisioni.
dreta,

@dreta i suoi presupposti vanno bene. Ha sottolineato che la sua massa per tutti gli oggetti è semplicemente "1" per ora, il che rende valide le sue sezioni di codice. A proposito, anche se Box2D può gestire direttamente le velocità, in qualche modo deve affrontare lo stesso problema. Se invece di applicare una forza, Box2D applica un impulso, in qualche modo deve comunque affrontare il fatto che l'impulso non scompare solo una volta separati gli oggetti. Tuttavia, è possibile che in realtà non si occupi affatto di questo e lasci che gli oggetti mantengano la loro energia (sarebbe così nel mondo reale dopo tutto)
TravisG

Risposte:


13

Innanzitutto, ti consiglio di utilizzare una libreria di fisica open source gratuita come Box2D e di concentrarmi solo sugli aspetti del tuo gioco che lo rendono unico! Se insisti nel reinventare la ruota, continua a leggere ... nota che tutti i motori fisici sono approssimazioni, e mentre il metodo che traccerò di seguito sarà più accurato del tuo modello attuale, i risultati di Box2D saranno molto più realistici.


Per un modo rapido per modellare una risoluzione di collisione più accurata di due oggetti A e B:

  1. Trova le posizioni subito prima della collisione. Lo state già approssimando: "trovando il vettore di penetrazione più breve e aggiungendolo alla posizione dell'AABB".
  2. Trova le velocità subito dopo la collisione usando la fisica newtoniana :
    • Nel caso in cui la massa sia hardcoded come 1, è sufficiente scambiare le velocità (questo non si applica agli oggetti statici che devono avere massa infinita):
      • Av = Bu
      • Bv = Au
    • Se gli oggetti A e B hanno masse diverse:
      • Av = (Au * (Am - Bm) + (2 * Bm * Bu)) / (Am + Bm)
      • Bv = (Bu * (Bm - Am) + (2 * Am * Au)) / (Am + Bm)
    • dove:
      • v: velocità dopo la collisione
      • u: velocità prima della collisione
      • m: massa (usa il maggior numero possibile per la massa di un oggetto fisso, statico)
  3. Impostare l'accelerazione su 0: l'accelerazione dalla collisione è stata spiegata sopra dai calcoli di velocità nel passaggio numero 2.

Dai un'occhiata al mio programma di asteroidi di esempio che dimostra questi concetti.


Quindi, tenere conto degli oggetti sovrapposti:

Come hai notato, l'uso della velocità per simulare oggetti impilati / a riposo non funziona bene: la velocità è la velocità che un oggetto si sta muovendo, quindi se si riposa su un oggetto statico, la velocità dovrebbe essere vicino a 0. Non ha senso aumentare la velocità di un oggetto per farlo apparire a riposo:

Se aggiungo l'accelerazione di gravità alla mia simulazione, la velocità del primo AABB dinamico continua a crescere anche quando è appoggiata sul secondo AABB statico. Alla fine, la velocità diventerà troppo grande e la collisione non verrà rilevata (l'AABB dinamico cadrà attraverso quello statico).

Ciò che dovrebbe realmente accadere è una forza di accelerazione che sta andando nella direzione opposta poiché la gravità dovrebbe annullare la gravità. (Questa è chiamata la normale forza di contatto). Una scorciatoia è semplicemente non applicare la gravità ai corpi che non sono nell'aria:

  • Un metodo per farlo è mantenere uno stato "radicato":
    • Non applicare la gravità agli oggetti in uno stato messo a terra.
    • Se un oggetto si scontra con un oggetto dal basso e la sua velocità è molto piccola, entra nello stato radicato.
    • Un oggetto esce dallo stato radicato quando la sua velocità verticale supera un certo valore positivo.

Aggiornare:

  • In parole povere, la fisica newtoniana afferma che l'energia totale prima e dopo una collisione deve corrispondere. Quando due oggetti si schiantano l'uno contro l'altro, la loro energia viene ridistribuita. L'energia è una combinazione di velocità e peso: le cose più pesanti e più veloci hanno più energia. È intuitivo. Tuttavia, ciò che non è intuitivo è il modo esatto in cui i pesi influiscono sulla ridistribuzione dell'energia.
  • La velocità di scambio è una scorciatoia solo per due corpi dinamici non fissi che hanno la stessa massa (gli oggetti fissi statici hanno masse infinite molto grandi).
  • La scorciatoia quando un corpo statico è fisso è: l'altro corpo dinamico e non fissato mantiene la stessa velocità; viene cambiato solo l'angolo (immagina un tavolo da biliardo quando una palla colpisce il binario. Il binario ha essenzialmente una massa infinita molto grande).
  • Per altri casi, come tre o più oggetti, è necessario risolvere le equazioni del moto newtoniano complete (conservazione della quantità di moto e conservazione dell'energia cinetica).
  • Non sono sicuro se le equazioni newtoniane per il movimento possano essere risolte per più di due corpi. Fortunatamente, tuttavia, tre oggetti non si scontrano quasi mai nello stesso momento. È sufficiente gestire i primi due corpi che si scontrano, quindi gestire le eventuali collisioni successive utilizzando le nuove velocità delle precedenti risoluzioni di collisione. Questa è una buona ragione per mantenere i passi del tempo di fisica il più piccolo possibile e gestire le collisioni prima che si verifichino eventuali penetrazioni.
  • Noterai nella mia demo di asteroidi che molti corpi vengono creati mentre le rocce più grandi vengono suddivise in più piccole. Tuttavia, gestisco sempre le collisioni tra coppie di corpi; mai gestire esplicitamente una collisione con più di due corpi.

Grazie per la risposta dettagliata. C'è qualcosa che non capisco però: le velocità di scambio funzionano bene in una collisione con 2 corpi - tuttavia, non vedo come possa funzionare quando più corpi (e anche corpi statici) si scontrano tutti allo stesso tempo. Anche senza gravità, avere un corpo dinamico allo stesso tempo si scontrano con un corpo statico e un altro corpo dinamico provoca problemi. Poiché la velocità viene scambiata, tutto dipende dall'ordine di collisione. Se il corpo statico viene urtato per ultimo, il corpo smetterà di muoversi. Se quello dinamico è, il corpo si muoverà di nuovo. Come è stato risolto?
Vittorio Romeo,

@Vee: buone domande! Tre + corpi e corpi statici sono due problemi separati. Ho affrontato entrambi in un aggiornamento. Riepilogo: gestire le collisioni due oggetti alla volta; i corpi statici hanno una massa infinita molto grande.
Leftium,

Il tuo modello per i contatti a riposo è strano. I contatti a riposo non sono solo per gravità, dovrebbero funzionare per qualsiasi forza. Il modo più semplice che funziona è semplicemente rimuovere la velocità acquisita a causa dell'accelerazione nel frame precedente al contatto. Anche per le piccole velocità è possibile rimuovere completamente la restituzione, anche se i calcoli non tengono conto della restituzione. Questo approccio funziona per tutte le forze, è facile da implementare e sembra abbastanza buono.
dreta,

16

Per risolvere questo problema è necessario regolare la posizione e possibilmente la velocità. I motori di fisica del corpo rigido hanno un solutore che marcia gli oggetti in avanti nel tempo usando le leggi del moto di Newton, risolvendo allo stesso tempo i vincoli di non penetrazione e l'attrito. Questi motori sono in grado di calcolare la giusta combinazione di movimento lineare e angolare per creare traiettorie plausibili.

Se vuoi solo risolvere la sovrapposizione, puoi usare pseudo velocità che generano traiettorie di separazione senza aggiungere slancio. Questo viene fatto nel solutore di posizione di Box2D.

Consiglio di ottenere le mie presentazioni GDC dal 2006 al 2007 qui:

http://code.google.com/p/box2d/downloads/list

Inoltre, puoi guardare Box2D Lite per un'implementazione semplificata.


+1 per l'osservazione della necessità di regolare anche la posizione. Poche persone si concedono questo, ma per aumentare la stabilità della simulazione, la maggior parte dei motori imbroglia regolando direttamente le posizioni. Tutto sommato, se è plausibile, funziona per i giochi.
teodron,

Grazie per la risposta. Volevo sapere qualcosa che probabilmente mi mancava nella presentazione: i corpi statici sono gestiti in modo speciale in Box2D? Voglio dire: cosa succede quando un corpo dinamico colpisce un corpo statico?
Vittorio Romeo,

2

inserisci qui la descrizione dell'immagine

Nel mondo reale, non esiste una forza che "spinga" un corpo al di fuori di un altro perché gli oggetti non si penetrano mai l'un l'altro. La cosa più vicina è la forza normale : creata al momento del contatto nelle collisioni del mondo reale, impedisce in primo luogo la penetrazione.

L'angolo di questa forza normale è perpendicolare alla superficie di contatto dei due oggetti in collisione. L'entità dipende da quanta forza è necessaria per impedire la penetrazione. (Notare che deve essere utilizzato solo il componente y della forza normale a meno che non siano modellate anche altre forze come la forza di attrito).

Mentre è possibile modellare esplicitamente la forza normale, è più semplice modellare solo i suoi effetti:

  1. Prevenire l'intersezione di oggetti mediante:
    • Regolazione delle velocità risolvendo le collisioni al momento dell'impatto. (migliore)
    • Regolazione manuale delle posizioni dei corpi in modo che non si intersecino. (più semplice) Lo stai già facendo "trovando il vettore di penetrazione più breve e aggiungendolo alla posizione dell'AABB".
  2. Non applicare la gravità dove ci sarebbe una forza normale che annulla la forza di gravità.
    • Un oggetto in contatto con un altro oggetto sottostante è soggetto alla forza normale. Quindi si tratta di tenere traccia di quegli oggetti. (In realtà qualsiasi oggetto a contatto dovrebbe avere una forza normale applicata, ma non tutti questi avranno un effetto netto rispetto alla gravità.)
    • Se si desidera aggiungere oggetti che possono scorrere verso il basso rispetto ad altri oggetti inclinati, è necessario aggiungere la forza di attrito e il componente x della forza normale.

L'ho descritto in modo leggermente diverso nell'altra mia risposta, che riguarda più le collisioni in generale .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.