2011-05-11 4 views
5

Primera nota: matemáticamente, no soy tan habilidoso en absoluto.Cómo utilizar una fórmula de parábola en AS3 para disparar una flecha que siempre interceptará un punto determinado

Jugué un juego en el iPhone hace un tiempo en el que presionas un punto, y una flecha dispara desde tu castillo, que siempre se cruza con el punto que presionaste. Quería hacer un juego similar, pensando que sería una tarea fácil y rápida; luego me di cuenta de que las matemáticas para esto están realmente más allá de mi nivel de habilidad.

Supongo que están usando una fórmula de parábola o algo que determinaría la velocidad y el ángulo necesarios cuando se lanza la flecha para que la flecha siempre se cruce con el punto en el que se hace clic.

Solo recuerdo vagamente cómo funcionan las parábolas de la escuela y no tienen ninguna posibilidad de encontrar fórmulas.

Cualquier ayuda matemática o ideas que pudieran ser más fáciles de implementar serían geniales.

Quiero terminar con una función en mi castillo, así:

package 
{ 
    import avian.framework.objects.AvElement; 

    public class Castle extends AvElement 
    { 
     /** 
     * Fires an arrow from this 
     * @param ix The x intersection point 
     * @param iy The y intersection point 
     */ 
     public function fire(ix:Number, iy:Number):void 
     { 
      var ar:Arrow = new Arrow(); 

      ar.x = x; 
      ar.y = y; 

      // define angle and velocity based on ix, iy 
      // ar.fireAngle = ?? 
      // ar.fireVelocity = ?? 

      parent.addChild(ar); 
     } 
    } 
} 

actualización según las preguntas en los comentarios:

No habrá fuerzas aplicadas a la flecha como el viento , fricción, etc. Además, el punto de partida de la flecha se fija durante todo el juego (en el castillo).

Aquí es una imagen de ejemplo de un poco más de claridad: Arrow path

de ser lo más claro posible:

  1. Flecha siempre comienza su viaje desde un punto fijo (por ejemplo: 40, 120).
  2. La flecha siempre debe interceptar una determinada coordenada.
  3. Una ruta lo más realista posible es algo que me gustaría lograr (obviamente, puedo disparar una flecha directamente para interceptar cualquier punto, pero la meta es hacer que la flecha se eleve primero, luego descender; coordinar en el punto más realista de su viaje).

Nota: para evitar el problema de que existan infinitos posibles parábolas - la velocidad de la flecha puede ser fijado - con tan sólo mirar a definir el ángulo de la flecha puede dejar al.

+1

Solo una nota rápida: también necesitará un punto de partida (así como también el destino) – Cameron

+0

¿Entonces hace clic donde desea que termine la flecha? Necesitarás coordenadas de origen también. El ángulo y la velocidad serán un rango de valores emparejados, a menos que uno sea fijo. Obviamente, la velocidad tiene que ser al menos la mínima para alcanzar la distancia en el ángulo óptimo. Pero si el ángulo es muy, entonces la velocidad también puede. Sin resistencia al aire, viento, en absoluto? Gravedad estándar de la tierra? – Orbling

+1

Este [gráfico y las ecuaciones debajo de él] (http://www.physics.brocku.ca/~aknigavk/1P21/Kinematics/projectile-motion-1.jpg) son útiles. – Orbling

Respuesta

8

La trayectoria de vuelo de un proyectil a través de un campo gravitatorio puede ser descrito aplicando el equations of motion

Las ecuaciones voy a utilizar son

1. v = u + at 
2. s = ut + (at^2)/2 

donde

s = la distancia entre inicial y posiciones finales
u = la velocidad inicial
v = la velocidad final
a = la aceleración constante
t = el tiempo necesario para mover desde el estado inicial al estado final

Ok. Para animar esta flecha calcularemos su nueva velocidad y posición en intervalos regulares (cada cuadro) en función de su velocidad previa, posición y aceleración . La aceleración en este caso se debe completamente a la gravedad.

Permite simplificar y medir los intervalos de tiempo en cuadros en lugar de segundos. Esto nos da t = 1 para las ecuaciones anteriores que nos permite reescribir como

1. v = u + a*1   => v = u + a 
2. s = u*1 + (a*1^2)/2 => s = u + a/2 

Ahora en la dirección x la aceleración, a = 0 (no estamos tomando arrastre en cuenta). En la dirección y a = g, aceleración debido a la gravedad. Si nos rewite estas ecuaciones para resolver para cada eje obtenemos

para x:

1. vx = ux + 0  => vx = ux (no change so we'll ignore this) 
2. sx = ux + 0/2  => sx = ux (convenient eh?) 

para y:

1. vy = uy + g 
2. sy = uy + g/2 

Por lo que permite conectarlos a un script de ejemplo

public class Arrow extends Sprite 
{ 
    //g is constant 
    //it's actually closer to 10 but this is our world 
    public static const g:Number = 2; 

    //our arrow 
    private var arrow:Shape; 

    //start velocities 
    private var ux:Number; 
    private var uy:Number; 

    public function Arrow() 
    { 
     arrow = new Shape(); 
     arrow.graphics.lineStyle(1, 0); 
     arrow.graphics.lineTo(30, 0); 
    } 

    public function fire(vx:Number, vy:Number):void 
    { 
     ux = vx; 
     uy = vy; 
     addChild(arrow); 
     addEventListener(Event.ENTER_FRAME, fly); 
    } 

    private function fly(e:Event):void 
    { 
     //lets use our equations 
     var sx:Number = ux;  //distance moved in x dir 

     var vy:Number = uy + g //new velocity in y dir 
     var sy:Number = uy + g/2 //distance moved in y dir 

     //apply to arrow 
     arrow.x += sx; 
     arrow.y += sy; 

     //save new y velocity 
     uy = vy; 

     //extra bonus rotation of arrow to point in the right direction 
     arrow.rotation = Math.atan2(uy, ux) * 180/Math.PI; 

    } 

} 
+0

Parece una pareja realmente convincente, tendré que probarlo cuando tenga un momento. +1 para el esfuerzo de cualquier manera :) – Marty

+0

@Marty Wallace No hay problema, disfruté escribiéndolo, espero que ayude – meouw

0

Puedes hacerlo básicamente sin matemáticas:

import flash.display.Shape; 
import flash.events.Event; 

public class Arrow extends Shape 
{ 
    private var xVelocity:Number; 
    private var yVelocity:Number; 

    public function Arrow(fireAngle:Number, fireVelocity:Number) 
    { 
     xVelocity = Math.cos(fireAngle) * fireVelocity; 
     yVelocity = Math.sin(fireAngle) * fireVelocity; 

     graphics.beginFill(0); 
     graphics.drawCircle(0, 0, 5); 
     graphics.endFill(); 

     addEventListener(Event.ENTER_FRAME, enterFrameHandler); 
    } 
    private function enterFrameHandler(ev:Event):void 
    { 
     x += xVelocity; 
     y += yVelocity; 
     yVelocity += 1; 
    } 
} 
+0

¿Es tan difícil de ejecutar y ver? –

+0

Disculpe, esto dará el efecto de lo que quiero, pero el objetivo es que la flecha se cruce con un punto. Tener la maniobra de la flecha de manera realista no es una preocupación. – Marty

Cuestiones relacionadas