Consejo rápido Detección de colisión entre un círculo y una línea

En mi Sugerencia rápida anterior, vimos la idea de la detección de colisiones en general, y específicamente la detección de colisiones entre un par de círculos. En este Consejo rápido, analizaremos la detección de una colisión entre un círculo y una línea.


Este es el resultado en el que trabajaremos. Haga clic en el botón Reiniciar para volver a colocar todos los círculos en la parte superior del escenario y verlos caer..

Tenga en cuenta que los círculos chocan con la línea incluso fuera del segmento que se dibuja. Mi próximo Consejo rápido mostrará cómo solucionar este problema..


Paso 1: La Idea General

Para verificar si algún círculo ha chocado con una línea, tenemos que verificar el longitud perpendicular De la línea al círculo. Observe el siguiente diagrama.

Del diagrama anterior se desprende claramente que los casos 3 y 4 deberían detectar una colisión entre el círculo y la línea. Entonces, concluimos que si la longitud perpendicular (marcada en rojo) es igual o menor que el radio del círculo, se produjo una colisión debido a que el círculo tocó o se superpuso a la línea. La pregunta es, ¿cómo calculamos esta longitud perpendicular? Bueno, los vectores pueden ayudar a simplificar nuestro problema..


Paso 2: Línea Normal

Para dibujar una línea en el escenario, necesitamos dos coordenadas (c1 y c2). La línea dibujada de c1 a c2 formará un vector que apunta a c2 (observe la dirección de la flecha).

A continuación, necesitamos encontrar la línea de normal. La línea normal es otra línea que hace 90 ° con la línea original, y se interseca con ella en un punto. A pesar de que la línea normal es otra línea más, la forma vectorial de la normal puede identificarse como la izquierda o Correcto normal en relación con el vector de la línea. La normal izquierda es el propio vector de línea, girado -90 °. La normal correcta es la misma pero girada 90 °. Recuerde, el eje y en el espacio de coordenadas de Flash se invierte en comparación con el eje y en un gráfico típico, por lo que la rotación positiva es hacia la derecha y la rotación negativa hacia la izquierda.


Paso 3: Proyección a la izquierda normal

La normal izquierda se usa en nuestro intento de calcular la longitud perpendicular entre el círculo y la línea. Los detalles se pueden encontrar en el siguiente diagrama.. UNA se refiere a un vector que apunta desde c1 al circulo La longitud perpendicular en realidad se refiere al vector A proyección a la izquierda normal. Derivamos esta proyección utilizando trigonometría: es | A | Coseno (theta), dónde | A | se refiere a la magnitud del vector UNA.

El enfoque más simple es hacer uso de operaciones vectoriales, específicamente el producto punto. A partir de la ecuación del producto punto, reorganizamos los términos para que lleguemos a la segunda expresión que se muestra a continuación. Tenga en cuenta que el lado derecho de la segunda ecuación es la proyección que queríamos calcular!

También tenga en cuenta que el lado izquierdo y derecho de la ecuación producirá finalmente el mismo resultado, aunque sea diferente en sus enfoques. Entonces, en lugar de usar el lado derecho de la ecuación, podemos optar por el lado izquierdo de la ecuación. Para llegar fácilmente al resultado final, es favorable usar la izquierda porque las variables se pueden resolver fácilmente. Si insistimos en usar el derecho de ecuación, tendríamos que impulsar ActionScript a través de un trabajo matemático riguroso para calcular el ángulo theta. Concluimos con el siguiente diagrama..

(* Nota adicional: si el círculo cae debajo del vector de línea, la longitud perpendicular calculada a partir de la fórmula en el diagrama anterior producirá un valor negativo).


Paso 4: Implementando la Detección de Colisiones Circle-Line

Ahora que hemos entendido matemáticamente el enfoque, procedamos a implementarlo en ActionScript. En esta primera sección, note que el vector de la línea está girando -90 ° para formar la normal izquierda..

 // declarando coordenadas x1 = 50; y1 = 100; x2 = 250; y2 = 150; // dibujo de línea graphics.lineStyle (3); graphics.moveTo (x1, y1); graphics.lineTo (x2, y2) // formando vectores de línea line = new Vector2D (x2 - x1, y2 - y1); leftNormal = line.rotate (Math.PI * -0.5);

En esta segunda sección, he resaltado los cálculos mencionados y la condición para verificar la colisión entre el círculo y la línea.

 actualización de funciones privadas (e: Evento): 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;   

Para aquellos que deseen investigar más a fondo, lo siguiente son extractos de los métodos utilizados en Vector.as

 / ** * Método para obtener la proyección del vector actual en un eje dado * @param axis Un eje donde el vector se proyecta en * @return La longitud de proyección del vector actual en un eje dado * / public function projectionOn (axis: Vector2D): Número return this.dotProduct (axis.normalise ())
 / ** * Método para realizar un producto de puntos con otro vector * @param vector2 Un vector para realizar un producto de puntos con el vector actual * @return Un número escalar de producto de puntos * / public function dotProduct (vector2: Vector2D): Number var componentX: Number = this._vecX * vector2.x; var componentY: Number = this._vecY * vector2.y; return componentX + componentY; 
 / ** * Método para obtener la unidad vectorial del vector actual * @return Una copia del vector normalizado * / public function normalize (): Vector2D devolver nuevo Vector2D (this._vecX / this.getMagnitude (), this._vecY / this getMagnitude ())
 / ** * Método para obtener la magnitud actual del vector * @return Magnitud del tipo Número * / función pública getMagnitude (): Número return Math.sqrt (_vecX * _vecX + _vecY * _vecY); 

Paso 5: El resultado

Presione el botón Reiniciar para volver a colocar todos los círculos en la parte superior del escenario. Tenga en cuenta que la colisión es entre el todo línea (incluyendo la sección no dibujada) y los círculos. Con el fin de limitar la colisión al segmento de línea solamente, permanezca atento a la siguiente sugerencia rápida.

Conclusión

Gracias por leer. Estad atentos para el próximo consejo..