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: falseEs 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):
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):
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
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.
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

Por HernanRivas el 21 de Agosto de 2007
http://www.geocities.com/~dr_ericlin/flash/indexgeo.html
Por Lightwave el 21 de Agosto de 2007
Estos principios son los que utilicé yo para hacer un arkanoid
Sigue asi con los tips de física aplicada, a mi por lo menos me interesan bastante.
Saludos.
Se te agradece Eternamente!!!!!!!! Muchisimas Gracias!!! En serio>!
felicitaciones!
Por ferranpujol_de vacac el 22 de Agosto de 2007
Por HernanRivas (lo el 22 de Agosto de 2007
Por HernanRivas (lo el 22 de Agosto de 2007
Por cierto, sobre la usabilidad del Ctrl y el Shift, gracias por el consejo, voy a tenerlo en cuenta para la próxima.
No, no me referia al ejemplo de las dos bolas y del shift y el control.
Hernán, antes de todo, dejar constancia de que esto no es una guerra porque no me parezcas simpatico ni nada parecido.
Si esto fuera un juicio te diria que acabas de caer en tu propia trampa: tu mismo dijiste que no era necesario complicarse haciendo las cosas físicamente perfectas. En este caso no se si te has complicado más o menos, has dicho que las equaciones eran Newtonianamente correctas (yo me fio) pero el último swf no es efectista. *Los otros si, muy buen trabajo
Con esto sólo quiero que veas que si un señor hace una web de física con una explicació al alcance de pocos o no muchos, no es posible simplificarlo sin afectar al resultado.
Y que quede claro que no intento destruir a nadie, ni menospreciar a nadie ni al trabajo de nadie.
Por RASUA24 el 17 de Mayo de 2009
Por anonimo el 03 de Marzo de 2011