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

En los Consejos rápidos anteriores, hemos analizado la colisión. detección: esencialmente, detectando que dos formas se han superpuesto. Ahora, estamos listos para ver la colisión reacción: hacer que algo suceda debido a una colisión. En este Consejo rápido, veremos las reacciones de reflexión y deslizamiento..


Vista previa del resultado final

Veamos el resultado final que lograremos al final de este tutorial. Cada demo en Flash tiene un botón de reinicio; Haz clic en él para restablecer la posición de los círculos en la parte superior del escenario..

La primera demo luce reflexión:

El segundo muestra corredizo:


Paso 1: La fórmula de reflexión

Repasé este tema varias rondas con los estudiantes, y la experiencia me ha enseñado que el enfoque directo de explicar las matemáticas vectoriales a los resultados más recientes en rostros en blanco y mentes confusas. Así que, en lugar de presentar una conferencia de matemáticas aquí, referiré a aquellos que estén interesados ​​en investigar este tema más a la página de reflexión de Wolfram..

Aquí, simplificaré mis explicaciones con los diagramas a continuación. Recuerda la suma de vectores:

Ahora, observa el diagrama de abajo. A es la velocidad del círculo antes de una colisión, y A 'es su velocidad después de la colisión.

Es obvio que A '= A + 2 V (Apag), dónde VIRGINIApag) representa el vector con una magnitud de Apag, en la dirección de la izquierda normal. (Puedes ver esto siguiendo las líneas discontinuas).

Para obtener VIRGINIApag), Proyectaremos A hacia la izquierda normal.


Paso 2: Implementación

Aquí viene la implementación de ActionScript de la reflexión. He resaltado las partes importantes. La línea 67 - 69 es para calcular VIRGINIApag) (v_leftNormSeg2) y la línea 70 implementa la fórmula. Puede consultar el ActionScript completo en Reaction1.as.

(Debería reconocer la mayoría del código del Consejo rápido anterior).

 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); var c1_circle_onLine:Number = c1_circle.projectionOn(line); //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius && line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude()) //redefine velocity var v_leftNormSeg2:Vector2D = leftNormal.clone(); var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal)) v_leftNormSeg2.setMagnitude(leftNormSeg2_mag); velos[i] = velos[i].add(v_leftNormSeg2.multiply(2));  circles[i].x += velos[i].x; circles[i].y += velos[i].y;  

Paso 3: Una versión interactiva

Tenga en cuenta que esta fórmula de reflexión es aplicable a la línea de cualquier gradiente. De hecho, puede programar su línea para que sea ajustable en tiempo de ejecución y verla reflejando círculos como la presentación de Flash a continuación. Simplemente haga clic y arrastre hacia el extremo inferior de la redefinición.


Paso 4: Deslizamiento a lo largo de la línea

El concepto de deslizamiento a lo largo de la línea es casi idéntico al reflejo. Observe el siguiente diagrama.

El vector de diapositiva es A '= A + V (Apag) con VIRGINIApag) representando un vector con magnitud de UNApag. De nuevo, para obtener unapag Proyectaremos A hacia la izquierda normal.

Tenga en cuenta que a medida que el círculo se desliza a lo largo de la línea, choca con la línea. Por supuesto, los puntos de colisión difieren entre los círculos que chocan en la línea, por lo que algunos se superponen a lo largo de la línea. Esto no se ve bien, así que tendremos que reposicionarlos..


Paso 5: Redefinir la ubicación

Ahora, reposicionemos los círculos en la línea mientras mantenemos su contacto con la línea. Hacer referencia al diagrama de abajo.

Una variable importante para calcular es la proyección de A a lo largo de la línea. El radio del círculo está fácilmente disponible, y ya tenemos B, por lo que podemos formar los vectores de B y C. Agregar los dos nos dará A, la ubicación exacta para reposicionar el círculo. Sencillo!

La siguiente presentación Flash está codificada de acuerdo con la idea mencionada. Pero hay un problema: los círculos tiemblan a lo largo de la línea..

Hay un detalle final que nos perdimos. El diagrama de arriba muestra que la magnitud de C debería ser equivalente al radio del círculo. Sin embargo, esto colocará el círculo por encima de la línea. Como no se detecta ninguna colisión allí, el círculo caerá nuevamente sobre la línea, lo que a su vez marcará la detección de colisión y hará que el círculo se reposicione.

Este ciclo se repetirá hasta que haya pasado el final del segmento de línea; El resultado visual de este ciclo es el efecto de jittering..

La solución a este problema es establecer la magnitud de C en un poco menos que el radio del círculo: (radio del círculo - 1), decir. Observe la demostración de Flash a continuación que utiliza esta idea:


Paso 6: Implementación

Así que aquí está el fragmento de código ActionScript importante para deslizarse a lo largo de la línea. He resaltado las partes importantes..

 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); var c1_circle_onLine:Number = c1_circle.projectionOn(line); //check for collision if (Math.abs(c1_circle_onNormal) <= circles[i].radius) //check if within segment //if within segment, reposition and recalculate velocity if (line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude())  //repostion circle var v_lineSeg:Vector2D = line.clone(); v_lineSeg.setMagnitude(c1_circle_onLine); var v_leftNormSeg1:Vector2D = leftNormal.clone(); v_leftNormSeg1.setMagnitude(circles[i].radius - 1); //v_leftNormSeg1.setMagnitude(circles[i].radius); //uncomment this to check out the error: jittering effect var reposition:Vector2D = v_lineSeg.add(v_leftNormSeg1) circles[i].x = x1+reposition.x; circles[i].y = y1+reposition.y; //redefine velocity var v_leftNormSeg2:Vector2D = leftNormal.clone(); var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal)) v_leftNormSeg2.setMagnitude(leftNormSeg2_mag); var veloAlongLine:Vector2D = velos[i].add(v_leftNormSeg2); circles[i].x += veloAlongLine.x; circles[i].y += veloAlongLine.y;  //if not in segment (e.g. slide out of segment), continue to fall down else  circles[i].x += velos[i].x; circles[i].y += velos[i].y;   //No collision in the first place, fall down else  circles[i].x += velos[i].x; circles[i].y += velos[i].y;   

Conclusión

Espero que esto sea de ayuda. Gracias por leer. Avisarme si hay preguntas, y te veré a continuación Consejo rápido.