Suggerimento rapido rilevamento collisione tra un cerchio e una linea

Nel mio precedente suggerimento rapido, abbiamo esaminato l'idea del rilevamento delle collisioni in generale, e in particolare nel rilevare le collisioni tra una coppia di cerchi. In questo suggerimento, cercheremo di rilevare una collisione tra un cerchio e una linea.


Questo è il risultato su cui lavoreremo. Fai clic sul pulsante Riavvia per riposizionare tutti i cerchi nella parte superiore dello stage e guardarli cadere.

Si noti che i cerchi si scontrano con la linea anche al di fuori del segmento che viene disegnato. Il mio prossimo suggerimento rapido mostrerà come risolvere questo problema.


Step 1: L'idea generale

Per verificare se una qualsiasi cerchia si è scontrata con una linea, dobbiamo controllare il lunghezza perpendicolare dalla linea al cerchio. Osservare lo schema qui sotto.

È chiaro dal diagramma sopra che i casi 3 e 4 dovrebbero rilevare una collisione tra il cerchio e la linea. Quindi concludiamo che se la lunghezza perpendicolare (indicata in rosso) è uguale o inferiore al raggio del cerchio, si verifica una collisione dovuta al cerchio che tocca o si sovrappone alla linea. La domanda è, come calcoliamo questa lunghezza perpendicolare? Bene, i Vettori possono aiutare a semplificare il nostro problema.


Passaggio 2: linea normale

Per disegnare una linea sul palco, abbiamo bisogno di due coordinate (c1 e c2). La linea tracciata da c1 a c2 formerà un vettore che punta a c2 (notare la direzione della freccia).

Successivamente, dobbiamo trovare la linea normale. La linea è normale è un'altra linea che fa 90 ° con la linea originale, e si interseca con essa in un punto. Nonostante la normale linea sia ancora un'altra linea, la forma vettoriale normale può essere ulteriormente identificata come la sinistra o destra normale rispetto al vettore della linea. La sinistra normale è il vettore di linea stesso, ruotato di -90 °. Il normale giusto è lo stesso ma ruotato di 90 °. Ricorda, l'asse y nello spazio delle coordinate di Flash è invertito rispetto all'asse y su un grafico tipico, quindi la rotazione positiva è in senso orario e la rotazione negativa è antioraria.


Passaggio 3: proiezione a sinistra normale

La sinistra normale è usata nel nostro tentativo di calcolare la lunghezza perpendicolare tra il cerchio e la linea. Dettagli possono essere trovati nello schema qui sotto. UN si riferisce a un vettore che punta da c1 al cerchio. La lunghezza perpendicolare si riferisce effettivamente ai vettori A proiezione a sinistra normale. Deriviamo questa proiezione usando la trigonometria: lo è | A | Coseno (theta), dove | A | si riferisce alla grandezza del vettore UN.

L'approccio più semplice consiste nell'utilizzare le operazioni vettoriali, in particolare il prodotto punto. Partendo dall'equazione del prodotto punto, riorganizziamo i termini in modo da arrivare alla seconda espressione mostrata sotto. Nota che il lato destro della seconda equazione è la proiezione che volevamo calcolare!

Si noti inoltre che il lato sinistro e destro dell'equazione produrranno in definitiva lo stesso risultato, anche se diversi nei loro approcci. Quindi, invece di usare il lato destro dell'equazione, possiamo optare per il lato sinistro dell'equazione. Per arrivare facilmente al risultato finale, è preferibile utilizzare la sinistra perché le variabili possono essere facilmente risolte. Se insistiamo nell'usare il diritto di equazione, dovremmo spingere ActionScript attraverso un rigoroso lavoro matematico per calcolare l'angolo theta. Concludiamo con lo schema qui sotto.

(* Nota aggiuntiva: se il cerchio scende al di sotto del vettore della linea, la lunghezza perpendicolare calcolata dalla formula nel diagramma sopra produrrà un valore negativo).


Passaggio 4: implementazione del rilevamento delle collisioni Circle-Line

Ora che abbiamo capito matematicamente l'approccio, procediamo con l'implementazione in ActionScript. In questa prima sezione, nota che il vettore della linea viene ruotato di -90 ° per formare la sinistra normale.

 // dichiarazione delle coordinate x1 = 50; y1 = 100; x2 = 250; y2 = 150; // drawing line graphics.lineStyle (3); graphics.moveTo (x1, y1); graphics.lineTo (x2, y2) // formando line lines line = new Vector2D (x2 - x1, y2 - y1); leftNormal = line.rotate (Math.PI * -0.5);

In questa seconda sezione, ho evidenziato i calcoli citati e la condizione per verificare la collisione tra cerchio e linea.

 aggiornamento della funzione privata (e: Event): void for (var i: int = 0; i < circles.length; i++)  //calculating line's perpendicular distance to ball var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1); var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal); circles[i].y += 2; //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius) circles[i].y -= 2;   

Per coloro che desiderano approfondire ulteriormente, i seguenti sono estratti dei metodi utilizzati in Vector.as

 / ** * Metodo per ottenere la proiezione del vettore corrente su un determinato asse * @param axis Un asse su cui viene proiettato il vettore su * @return La lunghezza di proiezione del vettore corrente su un determinato asse * / proiezione di funzione pubblicaOn (asse: Vector2D): Number return this.dotProduct (axis.normalise ())
 / ** * Metodo per eseguire il prodotto punto con un altro vettore * @param vector2 Un vettore per eseguire un prodotto punto con vettore corrente * @return Un numero scalare di prodotti punto * / funzione pubblica dotProduct (vector2: Vector2D): Number var componentX: Number = this._vecX * vector2.x; var componentY: Number = this._vecY * vector2.y; return componentX + componentY; 
 / ** * Metodo per ottenere l'unità vettoriale del vettore corrente * @return Una copia del vettore normalizzato * / public function normalize (): Vector2D return new Vector2D (this._vecX / this.getMagnitude (), this._vecY / this. getMagnitude ())
 / ** * Metodo per ottenere l'ampiezza corrente del vettore * @return Magnitudine del tipo Numero * / funzione pubblica getMagnitude (): Number return Math.sqrt (_vecX * _vecX + _vecY * _vecY); 

Passaggio 5: il risultato

Premi il pulsante Riavvia per riposizionare tutti i cerchi nella parte superiore dello stage. Si noti che la collisione è tra il totale linea (compresa la sezione non disegnata) e cerchi. Per limitare la collisione solo al segmento di linea, resta sintonizzato per il prossimo suggerimento rapido.

Conclusione

Grazie per aver letto. Resta sintonizzato per il prossimo consiglio.