Comunidad de diseño web y desarrollo en internet online

Vuelvo a mi billar

Citar            
MensajeEscrito el 28 Abr 2008 05:31 pm
Muy buenas, abro un nuevo post para no continuar en el otro que ya escribí, aunque el tema es el mismo.

Vuelvo a mi juego de billar. Verán, después de lo que se estuvo hablando en el post que menciono arriba hice algunos cambios en mi programación y se hizo patente un problema del que creí que había conseguido zafarme: al tener ya la función que mueve las bolas controlada por un EnterFrame y no un Timer, en el momento de choque hay un instante en el que las bolas (a veces) por poco \"atraviesan\" los bordes, y después, como la posición se corrige, lo hace de manera muy brusca en esos casos. Pues bien, quisiera intentarlo ahora con trigonometría, tal y como me dijo solisarg (no olvidé su código):

Código :

var game:Object = {};
game.numBalls = 2;
for (var i = 1; i<=game.numBalls; ++i) {
   var name:String = \"ball\"+i;
   game[name] = {};
   game[name].clip = _root[name];
   game[name].xpos = game[name].clip._x;
   game[name].ypos = game[name].clip._y;
   game[name].radius = game[name].clip._width/2;
   game[name].xmov = 0;
   game[name].ymov = 0;
}
game.ball1.xmov = 0;
game.ball1.mass = 1;
game.ball1.ymov = 2;
game.ball2.mass = 1;
game.ball2.ymov = 0;
function moveBalls() {
   for (var i = 1; i<=game.numBalls; ++i) {
      var ob:Object = game[\"ball\"+i];
      ob.tempx = ob.xpos+ob.xmov;
      ob.tempy = ob.ypos+ob.ymov;
   }
}
function renderBalls() {
   for (var i = 1; i<=game.numBalls; ++i) {
      var ob = game[\"ball\"+i];
      ob.xpos = ob.tempx;
      ob.ypos = ob.tempy;
      ob.clip._x = ob.xpos;
      ob.clip._y = ob.ypos;
   }
}
function ball2BallReaction(b1:Object, b2:Object, x1:Number, x2:Number, y1:Number, y2:Number, time:Number) {
   //get the masses
   var mass1:Number = b1.mass;
   var mass2:Number = b2.mass;
   // -----set initial velocity variables
   var xVel1:Number = b1.xmov;
   var xVel2:Number = b2.xmov;
   var yVel1:Number = b1.ymov;
   var yVel2:Number = b2.ymov;
   var run:Number = (x1-x2);
   var rise:Number = (y1-y2);
   var Theta:Number = Math.atan2(rise, run);
   var cosTheta:Number = Math.cos(Theta);
   var sinTheta:Number = Math.sin(Theta);
   //Find the velocities along the line of action
   var xVel1prime:Number = xVel1*cosTheta+yVel1*sinTheta;
   var xVel2prime:Number = xVel2*cosTheta+yVel2*sinTheta;
   //Find the velocities perpendicular to the line of action
   var yVel1prime:Number = yVel1*cosTheta-xVel1*sinTheta;
   var yVel2prime:Number = yVel2*cosTheta-xVel2*sinTheta;
   // Conservation Equations
   var P:Number = (mass1*xVel1prime+mass2*xVel2prime);
   var V:Number = (xVel1prime-xVel2prime);
   var v2f:Number = (P+mass1*V)/(mass1+mass2);
   var v1f:Number = v2f-xVel1prime+xVel2prime;
   var xVel1prime:Number = v1f;
   var xVel2prime:Number = v2f;
   //Project back to Flash\'s x and y axes
   var xVel1:Number = xVel1prime*cosTheta-yVel1prime*sinTheta;
   var xVel2:Number = xVel2prime*cosTheta-yVel2prime*sinTheta;
   var yVel1:Number = yVel1prime*cosTheta+xVel1prime*sinTheta;
   var yVel2:Number = yVel2prime*cosTheta+xVel2prime*sinTheta;
   //change old pos
   b1.tempx = b1.xpos+bl.xmov*time;
   b1.tempy = b1.ypos+b1.ymov*time;
   b2.tempx = b2.xpos+b2.xmov*time;
   b2.tempy = b2.ypos+b2.ymov*time;
   b1.xmov = xVel1;
   b2.xmov = xVel2;
   b1.ymov = yVel1;
   b2.ymov = yVel2;
}
function ballToBallDetection(b1:Object, b2:Object) {
   //set the speed variables
   var xmov1:Number = b1.xmov;
   var ymov1:Number = b1.ymov;
   var xmov2:Number = b2.xmov;
   var ymov2:Number = b2.ymov;
   //set the position variables
   var xl1:Number = b1.xpos;
   var yl1:Number = b1.ypos;
   var xl2:Number = b2.xpos;
   var yl2:Number = b2.ypos;
   //define the constants
   var R:Number = b1.radius+b2.radius;
   var a:Number = -2*xmov1*xmov2+xmov1*xmov1+xmov2*xmov2;
   var b:Number = -2*xl1*xmov2-2*xl2*xmov1+2*xl1*xmov1+2*xl2*xmov2;
   var c:Number = -2*xl1*xl2+xl1*xl1+xl2*xl2;
   var d:Number = -2*ymov1*ymov2+ymov1*ymov1+ymov2*ymov2;
   var e:Number = -2*yl1*ymov2-2*yl2*ymov1+2*yl1*ymov1+2*yl2*ymov2;
   var f:Number = -2*yl1*yl2+yl1*yl1+yl2*yl2;
   var g:Number = a+d;
   var h:Number = b+e;
   var k:Number = c+f-R*R;
   //solve the quadratic equation
   var sqRoot:Number = Math.sqrt(h*h-4*g*k);
   var t1:Number = (-h+sqRoot)/(2*g);
   var t2:Number = (-h-sqRoot)/(2*g);
   if (t1>0 && t1<=1) {
      var whatTime:Number = t1;
      var ballsCollided:Boolean = true;
   }
   if (t2>0 && t2<=1) {
      if (whatTime == null || t2<t1) {
         var whatTime:Number = t2;
         var ballsCollided:Boolean = true;
      }
   }
   if (ballsCollided) {
      //Collision has happened, so throw a trace
      ball2BallReaction(b1, b2, xl1, xl2, yl1, yl2, whatTime);
   }
}
_root.onEnterFrame = function() {
   moveBalls();
   ballToBallDetection(game.ball1, game.ball2);
   renderBalls();
};


Pero quisiera comprender en primer lugar el fundamento teórico detrás de una comprobación de colisiones eficiente y eficaz (que deberá ser con trigonometría, me temo). Si no me equivoco, cada fotograma se comprueba con trigonometría y teniendo en cuenta la direción, ángulo y velocidad de las bolas si van a chocar con el objeto y, en función de si van a chocar o no, otra función les asigna después una posición en el plano y si es necesario un cambio de ángulo o de velocidad. ¿Es así, a grandes rasgos? Y si no, ¿algún experto podría desgranármelo un poco?

Muchísimas gracias

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 28 Abr 2008 05:43 pm

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 28 Abr 2008 08:41 pm
Okis, no tengo dicho libro pero me pondré manos a la obra. En vez de coger tu código trataré de trabajar desde cero; veré a ver qué consigo, y luego lo compartiré aquí. A lo mejor hago un bonito tip :-P

Saludos!

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 29 Abr 2008 02:00 am
Pues suerte y sin duda que conseguirás sacarle punta al lápiz, AS3 ofrece mejor rendimiento

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 02 May 2008 07:56 am
Estuve leyendo unos tips de HernanRivas sobre física para informarme y mencionaba la "distancia de penetración". Le envié un MP por si podía explicármelo un poco, pero su último mensaje en el foro es de hace semanas y aún no me ha respondido... ¿Alguien podría contarme un poco de qué va? Aunque creo que lo intuyo por el nombre, bien puedo estar equivocado...

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 02 May 2008 12:45 pm
"Distancia de penetración" .... se me ocurren muchas cosas :) ... pero no he leído a HernanRivas ... mejor que lo conteste él

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 08 May 2008 11:56 am
Cuando tengo las 15 bolas en el escenario más la blanca, me surge una escalofriante pregunta: ¿tengo que comprobar 16 posibles colisiones con 16 bolas diferentes? ¿256 comprobaciones? :shock: :shock: :shock: ¿O existe alguna manera de decir lo que en pseudocódigo sería "si este objeto choca con ALGO, return ALGO"?

Y otra cosa, ¿cómo puedo saber cuánto tiempo le lleva al procesador ejecutar una función? Quiero comprobar si es más rápido hallar la diferencia entre la distancia entre dos bolas y la suma de sus radios o utilizar la famosa función de GSkinner.

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 08 May 2008 12:26 pm
Tu lo has dicho, aparte hay que animar cada bola en función de la fuerza que recibe en el golpe (y nuevas posibles colisiones) INdispensable fórmulas afiladas antes que cualquier hitTest

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 08 May 2008 01:29 pm
OK, ya me ha quedado claro lo de las bolas...

Debería entonces comprobar si hay choque entre las bolas como he dicho primero, con las raíces cuadradas?

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 08 May 2008 01:38 pm
Tu lo has dicho


Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 16 May 2008 02:38 pm
AAARGH que desesperación me ha entrado!!!! :twisted:

Necesito a alguien que me ayude con esto, porque yo llevo un buen rato ya dándole vueltas y nada, no lo saco. ¿Qué les costaba hacer que el escenario de Flash no tuviese el eje Y invertido? :cry:

Estoy a tan sólo un paso de acabar el grueso de mi código para el billar, y me surge una duda muy importante:



Las líneas rojas gruesas son la dirección de la bola blanca que le he dado con el taco, la bola 9 está parada, el ángulo alfa es el que le he dado a la bola con el taco, los ángulos beta los desconozco son iguales, la línea discontinua azul es una tangente a ambas bolas, y el ángulo gamma lo conozco. ¡¡¡¿Cómo puedo saber el ángulo de salida de la bola, que sería el ángulo beta respecto a la línea discontinua azul?!!! ¡¡Llevo una hora dibujando triángulos y paralelas por doquier y no lo consigo, ayuda!! :cry:

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 16 May 2008 03:06 pm
En definitiva, tengo problemas cuando ambas bolas están en movimiento... :'(

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 16 May 2008 04:38 pm
Debería entonces comprobar si hay choque entre las bolas como he dicho primero, con las raíces cuadradas?

NO hallas la distancia al cuadrado y lo compruebas con la suma de radios al cuadrado

Código :

(bola1.x-bola2.x)*(bola1.x-bola2.x)+(bola1.y-bola2.y)*(bola1.y-bola2.y)<
     (bola1._width+bola2.width)*(bola1._width+bola2.width)/4

Siempre es más rápido una multiplicación que hayar una potencia o la raiz cuadrada
Para los ángulos debería coger lápiz y papel, pero supongo que deberías tener todos los ángulos referidos a la horizontal
[/quote]

Por Eliseo2

710 de clabLevel



 

firefox
Citar            
MensajeEscrito el 16 May 2008 07:33 pm
¿No te sirve esto?

Yo no calcularía de primeras el ángulo beta. Haría que la bola avanzase con la dirección del taco, y al colisionar con la otra bola, calcularía el rebote en función del ángulo que forman las dos bolas. Para eso te puede servir el teorema de conservación del momento lineal.

Por Zah

BOFH

4290 de clabLevel

27 tutoriales
5 articulos

  Bastard Operators From Hell Editores

Zaragoza, España

firefox
Citar            
MensajeEscrito el 16 May 2008 08:24 pm
Oh Zah qué grande muchas gracias, a ver si me leo lo del momento lineal y repaso a fondo tutorial a ver si se me ocurre alguna cosa :)

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 17 May 2008 05:09 pm
SÍIIIIIII



Aquí está la clave para conseguir saber el ángulo de salida de la bola tras chocar con otra, esté en movimiento o no. Ahora sólo tengo que hallar el módulo de la velocidad y listo :cool:

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 17 May 2008 05:58 pm
Argh, desisto...

Creo que voy a empezar de cero, copiando código de algún sitio -que estará en inglés, me temo-. Qué frustración... :-(

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 19 May 2008 07:29 pm
Bueno, ya copypasteé código de un lugar, lo he adaptado a AS3 y a mis necesidades y lo tengo casi listo, salvo el detalle que voy a decir a continuación. Lo llevaré a aportes cuando lo termine.

De momento dispongo de un ejemplo, para ir probando, que sin tener nada en la biblioteca se encarga de crear MC's redondos con nombre de clase Ball -que extiende de Sprite- y que en sí misma no tiene ningún método, salvo la asignación de algunas propiedades necesarias:

Código :

package 
{
   import flash.display.Sprite;

   public class Ball extends Sprite
   {
      public var radius:Number;
      private var color:uint;

      public var xmov:Number = 0;
      public var ymov:Number = 0;
      public var tempx:Number = 0;
      public var tempy:Number = 0;
      public var mass:Number = 0;
      public var bid:Number = 0;

      public function Ball(radius:Number = 20, color:uint = 0xb3d830):void
      {
         this.radius = radius;
         this.mass = this.radius;
         this.color = color;
         init();
      }

      public function init():void
      {
         graphics.beginFill(color);
         graphics.drawCircle(0, 0, radius);
         graphics.endFill();
      }
   }
}


Y en la clase principal, la que hace todo lo que he dicho, almacena según las va creando esas bolas en un Array. A continuación, la recorre con un bucle, y va moviendo, renderizando y comprobando colisiones con cada una de ellas:

Código :

public function Main():void
{
   balls = new Array();
   for (var ct:uint = 0; ct < ttl_balls; ct++)
   {
      var ball:Ball = new Ball(Math.random() * 50 + 10, 0xFFDD00);
      balls.push(ball);

      ball.bid = ct;

      ball.xmov = Math.random() * 10 + (Math.random() * 3);
      ball.ymov = Math.random() * 10 + (Math.random() * 3);

      ball.x = Math.random() * stage.stageWidth;
      ball.y = Math.random() * stage.stageHeight;

      addChild(ball);
   }
   addEventListener(Event.ENTER_FRAME, onEnterFrame);
}


Algo así. En la función onEnterFrame tengo lo siguiente:

Código :

private function onEnterFrame(event:Event):void
{
   var ball:Ball;

   for (ct = 0; ct < ttl_balls; ct++)
   {
      ball = balls[ct];

      moveBall(ball);
   }
   for (ct = 0; ct < ttl_balls; ct++)
   {
      ball = balls[ct];

      renderBall(ball);
   }
}


Entonces ahí viene mi problema: todas esas funciones, las que mueven y tal, se les pasa como parámetro un MovieClip de clase Ball. Entonces, si lo que quiero es tener varias bolas -porque si no, ya me dirán cómo jugamos al billar-, se me ocurren dos opciones: o poner todas esas bolas en la biblioteca y de clase base Ball, en cuyo caso no tengo ni idea de qué parámetro pasarle después a las funciones, o en la función constructora de Ball, hacer alguna cosa para que las bolas se dibujen y se coloreen solas, lo cual me parece un poco tedioso.

Sorry por el tochopost, ¿alguna sugerencia?

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 19 May 2008 07:37 pm
Por cierto, he aquí el ejemplo.

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 20 May 2008 12:50 pm
Lo que tienes que hacer es que TODOS tus símbolos de la biblioteca tengan como Clase base la Clase "Ball" que tienes definida -aunque procedan de una Clase distinta. Tus funciones recibirán como parámetro un objeto de la clase Ball
Por ejemplo, la bola blanca, cuando entra en alguna tronera, hará algo distinto que el resto de las bolas, sin embargo el "choque" debe ser igual que el resto

Por Eliseo2

710 de clabLevel



 

firefox
Citar            
MensajeEscrito el 20 May 2008 01:55 pm
Ajá, es ahí por donde iba, pero mi duda es: aunque su clase no sea Ball (aunque sí su clase base), ¿puedo designarlos como objetos Ball? ¿He de instanciarlos desde código, o deben estar ya en el escenario?

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 23 May 2008 10:59 am
Lo conseguí!!!!! :-P

Al final, copie las ecuaciones físicas de un tal Michael Battle, las adapté a AS3 basándome en la web de Morgan Newcomb y este es el resultado. Me temo que aún no hay rozamiento ni troneras de verdad, pero eso es cuestión de tiempo.

Ahora me gustaría saber si hay alguien tan amable y tan avezado en física que pudiera explicarme qué rayos significan estas ecuaciones, porque ni yo ni Michael Battle lo sabemos:

Código :

private function ballToBallReaction(b1:Ball, b2:Ball, dist:Number, xdif:Number, ydif:Number):void
   {
      // params
      //b1 - first ball in collision
      //b2 - second ball in collision
      //dist - distance between the middle of the two balls
      //xdif - diff between balls on the x axis
      //ydif - diff between balls on the y axis
   
      // This function is where the billiard goodness takes place.
      // It's physics madness... I'll explain the bits I think I understand

      // find the angle between the balls
      var angle = Math.atan2(ydif, xdif);

      var cosa = Math.cos(angle);
      var sina = Math.sin(angle);

      // find the current linear momentum on each axis for each ball
      // I think this rotates the coordinate system so that we can
      // determine a 2 dimensional collision
      var vx1p = cosa * b1.xmov + sina * b1.ymov;
      var vy1p = cosa * b1.ymov - sina * b1.xmov;
      var vx2p = cosa * b2.xmov + sina * b2.ymov;
      var vy2p = cosa * b2.ymov - sina * b2.xmov;

      // P = momentum?
      // V = velocity?
      var P = vx1p * b1.mass + vx2p * b2.mass;
      var V = vx1p - vx2p;

      vx1p = (P - b2.mass * V) / (b1.mass + b2.mass);
      vx2p = V + vx1p;

      // tell each ball how fast they're going on each axis
      b1.xmov = cosa * vx1p - sina * vy1p;
      b1.ymov = cosa * vy1p + sina * vx1p;
      b2.xmov = cosa * vx2p - sina * vy2p;
      b2.ymov = cosa * vy2p + sina * vx2p;

      // Work out the where the balls are colliding along the
      // "Line of Action" so that we can project them far enough
      // away from each other to no longer intersect
      var dif = ((b1.radius + b2.radius) - dist) / 2;

      var cosd = cosa * dif;
      var sind = sina * dif;

      // update their temporary positions
      b1.tempx -= cosd;
      b1.tempy -= sind;
      b2.tempx += cosd;
      b2.tempy += sind;
   }

Sobre todo las partes encabezadas por los comentarios //find the current linear momentum, // P = momentum? y // tell each ball how fast. Y dónde tendría que multiplicar por un coeficiente de restitución para que los choques no sean perfectamente elásticos.

¡Muchas gracias!

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 23 May 2008 11:01 am

Juanlu_001 escribió:

Al final, copie las ecuaciones físicas de un tal Michael Battle, las adapté a AS3 basándome en la web de Morgan Newcomb y ...


Estos son los enlaces respectivos


Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 23 May 2008 04:41 pm
En Inglés viene explicado "a grosso modo" en http://ericlin2.tripod.com/collision/collision5.html
En palabras viene a decir que cuando tenemos dos móviles moviéndose en distintas velocidades (entendidas las velocidades como un vector -con dirección e intensidad-), dividimos ese vector velocidad en dos uno en la dirección del choque y otra en la dirección perpendicular.

La componente en la dirección del choque se transmite de uno a otro. La dirección perpendicular permanece.

Por Eliseo2

710 de clabLevel



 

firefox
Citar            
MensajeEscrito el 28 May 2008 11:14 am
Mmm sigo sin comprender estas líneas:

Código :

// find the current linear momentum on each axis for each ball
// I think this rotates the coordinate system so that we can
// determine a 2 dimensional collision
var vx1p = cosa * b1.xmov + sina * b1.ymov;
var vy1p = cosa * b1.ymov - sina * b1.xmov;
var vx2p = cosa * b2.xmov + sina * b2.ymov;
var vy2p = cosa * b2.ymov - sina * b2.xmov;


Debe ser sólo una cuestión de trigonometría, pero no lo veo :crap:

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 28 May 2008 11:21 am
Siendo cosa y sina el coseno y el seno del ángulo que forman las bolas...

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 05 Jun 2008 11:32 am
Disculpad por revivir este post una y otra vez, pero es por no abir uno nuevo cada vez para preguntar lo mismo. Haciendo un estudio trigonométrico (qué pedante queda esto) de las fórmulas que escribí en mi penúltimo comentario he encontrado que efectivamente descompone la velocidad del móvil en dos componentes, una a lo largo de la línea de choque y otra perpendicular, aunque no sé muy bien de dónde sale. Además, como la masa de todas las bolas es la misma, he simplificado significativamente las ecuaciones, pero eso ya está resuelto. El caso es que quería preguntar una cosa: ¿es físicamente efectista y riguroso dividir la velocidad de cada bola en cada ciclo por una constante para conseguir que se detengan? No he encontrado otra manera mejor...

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox
Citar            
MensajeEscrito el 05 Jun 2008 11:55 am

Juanlu_001 escribió:

dividir la velocidad de cada bola en cada ciclo por una constante...


O multiplicar por 0.98...

Por Juanlu_001

Claber

690 de clabLevel

6 tutoriales

 

firefox

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.