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:
To be as clear as possible:
- Arrow always begins its journey from a fixed point (say: 40, 120).
- The arrow must always intercept a given coordinate.
- 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.
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;
}
}
You can do it with basically no math:
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;
}
}
精彩评论