Comunidad de diseño web y desarrollo en internet online

Física básica en Flash. Parte 3 Choque bidimensional

Artículos anteriores:

Parte 1: Integración de Verlet
Parte 2: Constraints



Bien, ahora vamos a adentrarnos en el tema de los choques bidimensionales entre discos.

Por obvios motivos, centré el tema en la programación en AS, pero sin olvidar la base física. Por lo tanto, este tutorial puede servir para entender los conceptos fundamentales del tema (si alguien está interesado desde el punto de vista de la física y no del código, asumo que estarán familiarizados con el choque unidimensional, en ese caso, lo que sigue será sólo una extensión de ese tema).

Sorprendentemente, no pude encontrar en ningún lado un tutorial que cubriera todos los temas que trato aquí (lo que habla bastante mal de mis capacidades de búsqueda) y me deja con ganas de saber si la carencia se debe a que todos suponen que este tema es obvio y que no necesita mayor explicación o porque para eso existen los profesores de física....



Entrando en tema... Porqué elegir discos y no cuerpos arbitrarios? Simplemente porque cuando uno intenta aplicar física a los juegos de Flash, descubre que lo más simple es usar círculos.

Porqué es más simple? Bien, se debe a que para detectar colisiones, solo hace falta calcular la distancia al objeto con el que queremos verificar la colisión, sabiendo que ésta no debería ser menor al radio del objeto en cuestión. Además, la distancia de penetración se calcula con muchísima facilidad (un tema ajeno a este tutorial).

A modo de ejemplo veamos las siguientes imágenes:



En éste caso, se puede ver como la colisión se puede calcular de la siguiente manera:

Código :

var colision = d < r; // Output: false
Es lógico que esto simplifica enormemente las cosas.



En éste otro ejemplo, las cosas son distintas, pero no tanto. Para saber si 2 círculos colisionan simplemente calculamos la distancia entre sus centros. El código sería el siguiente:

Código :

var colision = d < r1 + r2; // Output: false


Usando sólo estos datos podemos construir el siguiente ejemplo (mover el mouse para ver la colisión):



Podemos ver cómo el usar hitTest no es muy preciso (los círculos son tomados como cuadrados cuyo lado es igual al diámetro del círculo) mientras que el método de calcular las distancias es muy exacto. Además, aclaro que ambos métodos consumen más o menos la misma cantidad de recursos, y si pueden aproximar las raíces cuadradas, (o, aún mejor, usar distancias cuadradas y olvidarse de las raíces) la velocidad del segundo -y más preciso- método aumenta considerablemente.


Pero detectar la colisión es el aspecto fácil del tema. Lo más difícil es conseguir un rebote realista.


Por lo que de ahora en adelante, nos vamos a enfocar en el choque perfectamente elástico, donde los objetos que colisionan no se comprimen y no se pierde energía (casi el caso de las bolas de billar), con el fin de simplificar las cuentas. De todos modos, voy a intentar hacer un par de paréntesis para explicar choque inelástico y más adelante el choque plástico o perfectamente inelástico.


En realidad, lograrlo no es tan complejo como parece. Pero vamos a empezar con el caso más simple, una bola estática (en física se suele decir que tiene masa infinita o m1>>m2) y otra que se mueve libremente. Este caso es bastante simple, luego de la colisión, la segunda pelota va a moverse a igual velocidad (porque es elástico) pero en ángulo distinto. Lo importante es calcular ese ángulo.

Para eso veamos el primer ejemplo:



Supongo que el gráfico ilustra muy bien cómo se supone que rebota un objeto contra una superficie.


Aunque este tutorial habla del choque elástico, vale la pena hacer un paréntesis para discutir el choque inelástico. En este caso, la pelota y/o la pared se comprimen, por lo que pierde energía y luego del choque, la pelota se mueve con velocidad menor. Para trabajar con éstos choques, es necesario incluir el concepto del coeficiente de restitución (e).

Básicamente, este coeficiente indica cuánto varía el ángulo y la velocidad final en éste tipo de choques (en realidad, e determina cuánta energía se conserva luego del choque, lo que dije antes es la aplicación práctica de éste hecho. A saber, en los choques elásticos, e=1). La relación de los ángulos es la siguiente:

Código :

var angFinal = Math.atan (e * Math.tan (angInicial));
La velocidad final se calcula de dos maneras posibles:

Código :

var velFinal = (e * velInicial * Math.cos (AngInicial)) / Math.cos (angFinal);

Código :

var velFinal = (velInicial * Math.sin (AngInicial)) / Math.cos (angFinal);
De cualquier forma, esto es complicado y no es necesario, ya que podríamos simplemente multiplicar la velocidad por una constante arbitraria menor a 1 para conseguir un efecto similar y suficientemente realista para e similar a 1.


Ahora, volviendo con el choque elástico, tomamos esa idea básica, con la misma relación de alpha y beta, pero ahora la "superficie" será la línea tangente al círculo en el punto en que chocan las pelotas:



Entonces, todo se reduce a calcular ese ángulo y a efectuar unas operaciones aritméticas básicas. Nuestro primer ejemplo quedaría así (éste ejemplo es simple y creo que podrían hacerlo ustedes mismos):


Click para cambiar el ángulo
SHIFT para mover la bola grande


En ese ejemplo, el rebote se calcula con una fórmula muy simple que es (pseudocódigo):

Código :

var angFinal = 2 * tangente - angInicial;
La tangente la calculamos sumandole π/2 al ángulo que forman las bolas.



Pero eso es sólo el 50% de lo que queremos hacer. Lo más complicado es hacerlo con 2 bolas. En este caso, vamos a presuponer que las masas son iguales. De todos modos, las cuentas para distintas masas no son demasiado complejas, aunque se complican lo suficiente como para intentar con masas iguales siempre que sea posible; además, en la mayoría de los casos (pool, billar), las masas deben mantener esa relación.

En primer lugar, vamos a observar el caso más simple, una bola en reposo y otra que se dirige hacia ella:



Así, gráficamente, es muy fácil ver la relación entre la velocidad final de los 2 cuerpos y la velocidad inicial del cuerpo en movimiento. Además observamos que el ángulo que forman las direcciónes de las velocidades finales es igual a 90º (sólo si ambas masas son iguales).

Las cuentas quedan así:

Código :

var velFinal1 = velInicial * Math.sin (angIni - angulo);
var velFinal2 = velInicial * Math.cos (angIni - angulo);
Básicamente, el código anterior asigna las velocidades dependiendo de el ángulo que forman el movimiento de la primer pelota (angIni) y el ángulo entre ambas pelotas (angulo).

Entonces, ya estamos en condiciones de armar un segundo ejemplo (como antes, insisto en que intenten hacerlo ustedes mismos):


Click para comenzar / reiniciar
SHIFT y CONTROL para mover las bolas



Como ya dije, las cuentas para distintas masas se complican y lo mismo para el caso del choque inelástico (que ya mencioné más arriba). De todas formas, [url]en ésta página[/url] pueden encontrar las fórmulas que se pueden adaptar muy fácilmente.

NOTA: A los que deseen visitar el link anterior, tengan en cuenta la orientación de los ejes. La página anterior es de física y no de física en Flash :wink:


Uf, ahora viene lo más interesante, el choque cuando ambos discos se hallan en movimiento. En este caso, las cosas se complican un poco y difieren bastante del caso anterior. Entonces, cabría preguntarse porqué me molesté en explicarlo. A decir verdad, el hecho de que sea más simple es una ventaja ya que muestra los conceptos básicos sin dejar de ser realista.

Ahora bien, como dije este caso es más complejo y sería ridículo intentar explicarlo sin una imagen (en realidad necesito 2).



En ésta imagen vemos el primer paso, descomponer el vector velocidad en otros 2 vectores, uno paralelo al ángulo entre las pelotas y otro perpendicular a éste (hacemos esto con ambas velocidades)



Ahora, intercambiamos los componentes de la velocidad paralelos al ángulo de choque.

Debería resultar obvio a estas alturas que este ejemplo es idéntico al que habíamos hecho antes, tomando en cuenta que la velocidad de una de las bolas es 0.


Antes de ir a la parte práctica, quiero explicar porqué se intercambian los componentes de la velocidad paralelos al ángulo de las pelotas.

Básicamente se debe a que sobre esa línea imaginaria las pelotas se transmiten su momento. Entonces, sobre esa línea se aplican las reglas del choque elástico en una dimensión (que indican justamente que se intercambia la velocidad cuando las masas son idénticas).



Entonces, a partir del ejemplo anterior, construimos otro, que ya nos permite un rango de posibilidades mucho más amplio.


No hay interacción



Bajar los archivos del tutorial



Cabe aclarar que todos los ejemplos están pensados en pos de la legibilidad y simpleza, ninguno tiene más de 80 líneas de código (incluyendo comentarios).



Y bien, ya llegamos al final. A continuación, dejo 3 apéndices donde voy a tratar un par de temas que (para mantener la unidad del tutorial) no pude incluir antes.




APENDICE 1: CENTRO DE MASA


Una de las formas de resolver estos problemas es hacerlo por medio del centro de masa. Incluso, puede que hasta resulte más cómo trabajar así cuando las bolas tienen distinta masa.

Supongo que ya sabrán que es el centro de masa (Cm de ahora en adelante). Es el punto en donde debemos sostener un objeto para que no se caiga. Lo que quizá no sabían es que se puede trabajar con el Cm incluso para 2 o más cuerpos separados.

Veamos el siguiente diagrama:



En este caso se observa que el objeto de la derecha es más grande (simbolizando que tiene más masa) y por lo tanto, el Cm de ambos cuerpos está más cerca de éste.

Ahora bien, la importancia del Cm puede no ser clara. Pero no importa cómo se muevan esos cuerpos (suponiendo que estuviesen perfectamente aislados) el centro de masa se va a mover con movimiento rectilíneo uniforme (es decir, sin aceleracion y sin cambiar de ángulo). Puede resultar difícil de creer, pero incluso aunque la gravedad los tirara hacia abajo, el Cm se movería de forma uniforme (aunque con aceleración vertical) como un objeto puntual en un caso de tiro oblicuo.

Si empleamos esto, podemos ver lo simples que pueden llegar a ser las fórmulas con bolas de masas distintas.

Es más, supongamos ahora una caja (seguimos en 2D), y pensemos en su Cm como un puntito en su centro.

Ahora, arrojamos la caja desde una altura y ésta cae, rebota, y gira en el aire. Aunque parezca mentira, su centro de masa se mueve como una pelota arrojada contra el piso que rebota.

Es decir, el centro de masa de un objeto se comporta como un punto sometido a las mismas fuerzas que el objeto extenso.



APENDICE 2: CHOQUE PLÁSTICO


Bien, el choque plástico es un caso particular de choque inelástico, donde e=0 (recordemos que en el choque elástico, e=1). Es decir que se pierde la mayor cantidad de energía posible (no necesariamente toda, aunque en algunos casos esto ocurre) en el choque. En éste caso, ambos objetos quedan pegados el uno con el otro.

En este caso las cuentas son muy simples (hasta demasiado), pero, es conveniente trabajar con las componentes horizontal y vertical de la velocidad (es decir, velocidad en el eje x y en el eje y) y no con la velociad y un ángulo (usar el esquema de Verlet simplifica las cosas).

Supongamos 2 objetos (de igual masa) que se mueven y quedan pegados. La velocidad en x del conjunto va a ser igual a la suma de las velocidades en ese mismo eje de los objetos por separado; lo mismo se aplica para el eje y.

En caso de que trabajemos con masas distintas podemos usar el Cm (que funciona perfectamente) o el teorema de la conservación de la cantidad de movimiento, que dice que la suma de las masas por las velociades de cada objeto se mantiene (si tenemos 2 objetos que quedan pegados, la suma de sus masas individuales por sus velocidades debe ser igual a la masa de ambos por la velociad final). En otras palabras:

Código :

var velFinal = (m1 * v1 + m2 * v2) / (m1 + m2)




APENDICE 3: USANDO VERLET


A primera vista, todo lo que hicimos (excepto el choque plástico) puede parecer incompatible con el esquema de Verlet de la primera parte. Pero en realidad no lo es en absoluto. En caso de que queramos usar Verlet simplemente calculamos la velocidad y el ángulo de movimiento en el momento de la colisión, para realizar los cálculos que vimos más arriba. Por supuesto, luego movemos un paso los objetos y dejamos que Verlet haga el resto.

Para calcular la velocidad y el ángulo de movimiento podemos usar los métodos de la clase Trig que incluí entre los ejemplos anteriores:

Código :

var velocidad = Trig.distancia ({_x:0 , _y:0}, {_x:velx, _y:vely});
var angulo = Trig.angulo ({_x:0 , _y:0}, {_x:velx, _y:vely});




Ahora sí, llegamos al verdadero final de la tercera parte ^^

fuente

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate