Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a parabola formula in AS3 for firing an arrow that will always intercept a given point

First note: mathematically, I'm not that skilled at all.

I played a game on iPhone a while back where you press a point, and an arrow fires from your castle which will always intersect the point you pressed. I wanted to make a similar game, thinking it would be an easy quick make; then I ran into the realization that the mathematics for this is actually beyond my skill level.

I'm assuming they're using a parabola formula or something which would determine the velocity and angle needed when the arrow is launched for the arrow to always intersect the clicked point.

I only vaguely remember how parabolas work from school and have no chance of working out any formulas.

Any mathematical help or ideas that might be easier to implement would be great.

I want to end up with a function in my castle like so:

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);
        }
    }
}

Update as per questions in comments:

There will be no forces applied to the arrow such as wind, friction, etc. Also, the starting point of the arrow is fixed throughout the game (at the castle).

Here is an example image for slightly more clarity: Arrow path

To be as clear as possible:

  1. Arrow always begins its journey from a fixed point (say: 40, 120).
  2. The arrow must always intercept a given coordinate.
  3. A realistic as possible path is something I'd like to achieve (obviously I can just fire an arrow straight to intercept any point, but the goal is to have the arrow first rise, then descend; passing through the desired coordinate at the most realistic point in its journey).

Note: To avoid the issue of there being infinite possible parabolas - the velocity of the arrow can be fixed - just look at defining the angle the arrow can leave at.

like image 953
Marty Avatar asked May 11 '11 01:05

Marty


1 Answers

The flight path of a projectile through a gravitational field can be described by applying the equations of motion

The equations I will use are

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

where

s = the distance between initial and final positions
u = the initial velocity
v = the final velocity
a = the constant acceleration
t = the time taken to move from the initial state to the final state

Ok. To animate this arrow we will calculate its new velocity and position at regular intervals (every frame) based on its previous velocity, position and acceleration. Acceleration in this case is entirely due to gravity.

Lets simplify and measure the time intervals in frames rather than seconds. This gives us t = 1 for the above equations allowing us to rewrite them as

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

Now in the x direction the acceleration, a = 0 (we're not taking drag into account). In the y direction a = g, acceleration due to gravity. If we rewite these equations for resolved for each axis we get

for x:

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

for y:

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

So lets plug them into a sample script

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;

    }

}
like image 138
meouw Avatar answered Nov 15 '22 04:11

meouw