Comunidad de diseño web y desarrollo en internet

Física básica en Flash. Parte 2: Constraints

Aunque este tip se justifica por sí mismo como introducción y desarrollo de los constraints, está pensado en base al tutorial anterior sobre Integración de Verlet. De todos modos, puede ser leido individualmente sin problema.

En primer lugar voy a explicar brevemente qué son los contraints.

Los constraints o restricciones son eso, restricciones. En este caso, de movimiento.

Imaginemos una barra de longitud L que cumpla las siguientes condiciones ideales, que no se pueda doblar, romper, estirar o comprimir (básicamente la definición de un cuerpo rígido ideal). Ahora, supongamos que tomamos 2 puntos cualesquiera de la misma, por motivos prácticos, en sus extremos.

Es claro que sin importar lo que ocurra, la distancia entre ambos puntos debe ser forzosamente L (la longitud de la barra), incluso aunque los movamos individualmente. Si pensamos esto en términos más normales o, mejor dicho, ejemplos palpables, esto resulta obvio y no requiere mayor explicación.

Supongamos que por motivos que no importan por el momento nos vemos obligados a mover las partículas y, también por motivos que no nos interesan por el momento, deseamos que las partículas permanezcan a la misma distancia.

En este caso, lo único que se conservaría es el ángulo que forman. Por lo tanto, si calculamos la distancia actual, le restamos la original (podría dar negativo, esto es correcto e importante) y la dividimos por 2, vamos a obtener cuánto debemos mover las partículas la una hacia la otra (el número negativo, haría que se alejen).

Paso a paso lo que hacemos es:

  • Calcular la distancia entre las partículas.
  • Calcular el ángulo que forman.
  • Calcular cuánto tenemos que moverlas.
  • Reubicarlas.


Si traducimos lo anterior a una función, obtenemos lo siguiente :

Código :

constraint = function (mc1:MovieClip, mc2:MovieClip, distancia:Number, elasticidad:Number, fijo1:Boolean, fijo2:Boolean):Void {
   //
   if (fijo1 && fijo2) {
      return;
   }
   //
   fijo1 = (fijo1 != true) ? false : true;
   fijo2 = (fijo2 != true) ? false : true;
   elasticidad = (elasticidad > 1 || typeof (elasticidad) != "number") ? 1 : ((elasticidad < 0) ? 0 : elasticidad);
   //
   var xdist = mc1._x - mc2._x;
   var ydist = mc1._y - mc2._y;
   var dist = Math.sqrt (xdist * xdist + ydist * ydist);
   var diff = dist - distancia;
   //
   if (Math.abs (diff) < .1) {
      return;
   }
   //
   var correccion = (fijo1 || fijo2) ? diff : diff / 2;
   var angulo = -Math.atan2 (xdist, ydist);
   //
   if (!fijo1) {
      mc1._x += correccion * Math.sin (angulo) * elasticidad;
      mc1._y -= correccion * Math.cos (angulo) * elasticidad;
   }
   //                            
   if (!fijo2) {
      mc2._x -= correccion * Math.sin (angulo) * elasticidad;
      mc2._y += correccion * Math.cos (angulo) * elasticidad;
   }
};

Aunque el código anterior está pensado para ser claro y simple de entender, realiza su trabajo como se supone que debe hacerlo.

Un ejemplo de cómo aplicamos el código anterior podría ser el siguiente:



En este caso, empleamos la variable elasticidad y obtenemos un efecto que podría tildarse de más orgánico (como en el juego Flow).

Además, empleamos una función que llama a la función constraints. La ventaja es que podemos fácilmente decidir cuántas iteraciones deseamos en el proceso de restringir.

Porqué tenemos que iterar? Es simple, el caso que veníamos analizando había sólo 2 partículas y un contraint. Con varios, la cosa se complica. Ya que satisfacer un constraint puede "desatisfacer" otro/s.

Cómo satisfacer todos los constraints al mismo tiempo? Bien, si uno lo analiza, es equivalente a resolver un sistema de ecuaciones bastante complejo. Pero, si satisfacemos una a una las restricciones, qué ocurre?

Exacto, el sistema se parece cada vez más a la solución final. Si repetimos el proceso infinitas veces, obtendríamos la posición exacta que deseamos.

Pero eso no es necesario, con 3 veces alcanza en la mayoría de los casos. Esto se debe a que este sistema no acumula errores. Un error pequeño al principio, significa un error menor luego de algunos fotogramas. Es decir, incluso con sólo una iteración obtendríamos el efecto deseado (aunque podría llegar a ser visualmente feo).

A estas alturas, ya puede resultar más clara la utilidad de la Integración de Verlet. Luego de modificar la posición de las partículas para satisfacer sus correspondientes sistemas de constraints, las hemos movido. Si además del código para las restricciones, le agregamos el que corresponde a la integración, vamos a ver cómo las partículas se unen para formar sólidos que rotan, rebotan, no se deforman y responden naturalmente a las colisiones.

Parece mentira? Pues no lo es:



Bajar los archivos del tutorial.

Igualmente, el ejemplo anterior es solo eso, un ejemplo. En realidad, si quisieramos convertir lo anterior en nuestro propio Half-life 2, vamos a necesitar un milagro, evitar que los objetos vibren cuando deberían estar quietos y un mejor sistema de detección de colisiones. Pero no hace falta ser demasiado crédulo para observar que no falta mucho para crear nuestra propia simulación física creible (no realista, sólo creible).

¿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