collisione cerchio-cerchio

Ho intenzione di sviluppare una partita a due in cui due palle (cerchi) si scontrano. Ora ho il problema di determinare il punto di collisione (in effetti, determinando se si scontrano nell’asse x / asse y). Ho un’idea che quando la differenza tra la coordinata y di 2 sfere è maggiore della differenza di coordinate x, allora si scontrano nel loro asse y, altrimenti si scontrano nel loro asse x. La mia idea è corretta? Ho implementato questa cosa nei miei giochi. Normalmente funziona bene, ma a volte fallisce. Qualcuno può dirmi se la mia idea è giusta? Se no, allora perché, ed è un modo migliore?

Per collisione sull’asse x, intendo il 1 °, il 4 °, il 5 ° o l’ottavo ottavo del cerchio, l’asse y indica il 2 °, il 3 °, il 6 ° o il 7 ° ottantesimo del cerchio.

Grazie in anticipo!

La collisione tra i cerchi è facile. Immagina ci siano due cerchi:

  • C1 con centro (x1, y1) e raggio r1;
  • C2 con centro (x2, y2) e raggio r2.

Immagina che ci sia una linea che corre tra questi due punti centrali. La distanza tra il centro e il bordo di ciascun cerchio è, per definizione, uguale al rispettivo raggio. Così:

  • se i bordi dei cerchi si toccano, la distanza tra i centri è r1 + r2;
  • qualsiasi distanza maggiore e i cerchi non toccano o collidono; e
  • meno e poi si scontrano.

Quindi puoi rilevare la collisione se:

(x2-x1)^2 + (y1-y2)^2 <= (r1+r2)^2 

il che significa che la distanza tra i punti centrali è inferiore alla sum dei raggi.

Lo stesso principio può essere applicato al rilevamento di collisioni tra sfere in tre dimensioni.

Modifica: se vuoi calcolare il punto di collisione, qualche trigonometria di base può farlo. Hai un triangolo:

  (x1,y1) |\ | \ | \ sqrt((x2-x1)^2 + (y2-y1)^2) = r1+r2 |y2-y1| | \ | \ | X \ (x1,y2) +------+ (x2,y2) |x2-x1| 

Le espressioni |x2-x1| e |y2-y1| sono valori assoluti. Quindi per l'angolo X:

  |y2 - y1| sin X = ------- r1 + r2 |x2 - x1| cos X = ------- r1 + r2 |y2 - y1| tan X = ------- |x2 - x1| 

Una volta ottenuto l'angolo, puoi calcolare il punto di intersezione applicandoli a un nuovo triangolo:

  + |\ | \ b | \ r2 | \ | X \ +-----+ a 

dove:

  a cos X = -- r2 

così

 a = r2 cos X 

Dalle precedenti formule:

  |x2 - x1| a = r2 ------- r1 + r2 

Una volta che hai aeb puoi calcolare il punto di collisione in termini di (x2, y2) di (a, b) come appropriato. Non hai nemmeno bisogno di calcolare seni, coseni o seni inversi o coseni per questo. O qualsiasi radice quadrata per quella materia. Quindi è veloce.

Ma se non hai bisogno di un angolo esatto o di un punto di collisione e vuoi solo l'ottante puoi ottimizzarlo ulteriormente comprendendo qualcosa sulle tangenti, che è:

  • 0 <= tan X <= 1 per 0 <= X <= 45 gradi;
  • tan X> = 1 per 45 <= X <= 90
  • 0> = tan X> = -1 per 0> = X => -45;
  • tan X <= -1 per -45> = X => -90; e
  • abbronzatura X = abbronzatura (X + 180) = abbronzatura (X-180).

Questi quattro intervalli di gradi corrispondono a quattro ottanti del cerchio. Gli altri quattro sono sfalsati di 180 gradi. Come dimostrato sopra, la tangente può essere calcasting semplicemente come:

  |y2 - y1| tan X = ------- |x2 - x1| 

Perdi i valori assoluti e questo rapporto ti indicherà quale dei quattro ottanti in cui si trova la collisione (secondo gli intervalli di tangenza sopra indicati). Per calcolare l'ottante esatto, confronta x1 e x2 per determinare quale è più a sinistra.

L'ottante della collisione sull'altro singolo è sfalsato (ottante 1 su C1 significa ottante 5 su C2, 2 e 6, 3 e 7, 4 e 8, ecc.).

Come dice il cleto, vuoi usare la sum dei raggi delle due palle. Vuoi calcolare la distanza totale tra i centri delle palle, come segue:

 Ball 1: center: p1=(x1,y1) radius: r1 Ball 2: center: p2=(x2,y2) radius: r2 collision distance: R= r1 + r2 actual distance: r12= sqrt( (x2-x1)^2 + (y2-y2)^2 ) 

Una collisione avverrà ogni volta (r12

 collision vector: d12= (x2-x1,y2-y1) = (dx,dy) actual distance: r12= sqrt( dx*dx + dy*dy ) 

Nota che hai già calcolato dx e dy sopra quando stai calcolando la distanza effettiva, quindi potresti anche tenerne traccia per scopi come questo. Puoi usare questo vettore di collisione per determinare la nuova velocità delle palle – finirai per ridimensionare il vettore di collisione di alcuni fattori e aggiungerlo alle vecchie velocità … ma, per tornare alla collisione effettiva punto:

 collision point: pcollision= ( (x1*r2+x2*r1)/(r1+r2), (y1*r2+y2*r1)/(r1+r2) ) 

Per capire come trovare la nuova velocità delle palle (e in generale per dare più senso a tutta la situazione), probabilmente dovresti trovare un libro di fisica delle scuole superiori, o l’equivalente. Sfortunatamente, non conosco un buon tutorial web – suggerimenti, qualcuno?

Oh, e se voglio ancora seguire la cosa sull’asse x / y, penso che tu abbia capito bene:

 if( abs(dx) > abs(dy) ) then { x-axis } else { y-axis } 

Per quanto riguarda il motivo per cui potrebbe fallire, è difficile dirlo senza ulteriori informazioni, ma potresti avere un problema con le palle che si muovono troppo velocemente e passare l’una sopra l’altra in un singolo timestep. Ci sono modi per risolvere questo problema, ma il modo più semplice è assicurarsi che non si muovano troppo velocemente …

Questo sito spiega la fisica , ricava l’algoritmo e fornisce il codice per le collisioni di palle 2D.

Calcola l’ottante dopo questa funzione calcola quanto segue: posizione del punto di collisione rispetto al centro di massa del corpo a; posizione del punto di collisione rispetto al centro di massa del corpo a

 /** This function calulates the velocities after a 2D collision vaf, vbf, waf and wbf from information about the colliding bodies @param double e coefficient of restitution which depends on the nature of the two colliding materials @param double ma total mass of body a @param double mb total mass of body b @param double Ia inertia for body a. @param double Ib inertia for body b. @param vector ra position of collision point relative to centre of mass of body a in absolute coordinates (if this is known in local body coordinates it must be converted before this is called). @param vector rb position of collision point relative to centre of mass of body b in absolute coordinates (if this is known in local body coordinates it must be converted before this is called). @param vector n normal to collision point, the line along which the impulse acts. @param vector vai initial velocity of centre of mass on object a @param vector vbi initial velocity of centre of mass on object b @param vector wai initial angular velocity of object a @param vector wbi initial angular velocity of object b @param vector vaf final velocity of centre of mass on object a @param vector vbf final velocity of centre of mass on object a @param vector waf final angular velocity of object a @param vector wbf final angular velocity of object b */ CollisionResponce(double e,double ma,double mb,matrix Ia,matrix Ib,vector ra,vector rb,vector n, vector vai, vector vbi, vector wai, vector wbi, vector vaf, vector vbf, vector waf, vector wbf) { double k=1/(ma*ma)+ 2/(ma*mb) +1/(mb*mb) - ra.x*ra.x/(ma*Ia) - rb.x*rb.x/(ma*Ib) - ra.y*ra.y/(ma*Ia) - ra.y*ra.y/(mb*Ia) - ra.x*ra.x/(mb*Ia) - rb.x*rb.x/(mb*Ib) - rb.y*rb.y/(ma*Ib) - rb.y*rb.y/(mb*Ib) + ra.y*ra.y*rb.x*rb.x/(Ia*Ib) + ra.x*ra.x*rb.y*rb.y/(Ia*Ib) - 2*ra.x*ra.y*rb.x*rb.y/(Ia*Ib); double Jx = (e+1)/k * (Vai.x - Vbi.x)( 1/ma - ra.x*ra.x/Ia + 1/mb - rb.x*rb.x/Ib) - (e+1)/k * (Vai.y - Vbi.y) (ra.x*ra.y / Ia + rb.x*rb.y / Ib); double Jy = - (e+1)/k * (Vai.x - Vbi.x) (ra.x*ra.y / Ia + rb.x*rb.y / Ib) + (e+1)/k * (Vai.y - Vbi.y) ( 1/ma - ra.y*ra.y/Ia + 1/mb - rb.y*rb.y/Ib); Vaf.x = Vai.x - Jx/Ma; Vaf.y = Vai.y - Jy/Ma; Vbf.x = Vbi.x - Jx/Mb; Vbf.y = Vbi.y - Jy/Mb; waf.x = wai.x - (Jx*ra.y - Jy*ra.x) /Ia; waf.y = wai.y - (Jx*ra.y - Jy*ra.x) /Ia; wbf.x = wbi.x - (Jx*rb.y - Jy*rb.x) /Ib; wbf.y = wbi.y - (Jx*rb.y - Jy*rb.x) /Ib; } 

Il punto in cui si scontrano è sulla linea tra i punti medi dei due cerchi, e la sua distanza da entrambi i punti centrali è il raggio di quel rispettivo cerchio.

Sono d’accordo con le risposte fornite, sono molto buone.
Voglio solo indicarti una piccola trappola: se la velocità delle palline è alta, puoi semplicemente perdere la collisione, perché le cerchie non si incrociano mai per i passaggi indicati.
La soluzione è risolvere l’equazione sul movimento e trovare il momento corretto della collisione.

Ad ogni modo, se dovessi implementare la tua soluzione (confronto sugli assi X e Y) otterrai il buon vecchio ping pong! http://en.wikipedia.org/wiki/Pong
🙂

Per rispondere più direttamente alla tua domanda: Sì, in base alle regole e ai requisiti che esponi, quelle sfere si scontrano sull’asse Y se la differenza in Y è maggiore della differenza in X quando le palle si toccano.

Se questo è ciò che stai implementando, otterrai una risposta corretta alla domanda “Collisione asse X o Y?”. Ma penso che la ragione per cui ricevi così tante risposte qui che non riesci a farne uso è neanche quella

  • stai facendo la domanda sbagliata (non qui – nel tuo programma); o

  • non stai usando la risposta correttamente.

Sono sicuro che molti di noi hanno programmato programmi di palline rimbalzanti, e sospetto che nessuno di noi abbia provato a modellare collisioni basate su ottanti e assi. Quindi sospetto che tu abbia un nuovo approccio molto originale o semplicemente lo stia sbagliando. Quindi, ti consiglio di tornare indietro e verificare il tuo metodo e le ipotesi.