Inverse trajectory determination-most ancient of computer probs.
by Stephen Clark · in Torque Game Engine · 07/25/2004 (2:52 pm) · 15 replies
So I have game gems 3 and I've implemented this, but I'm sure I'm doing something wrong, but I need another pair of eyes to figure it out. This would be a great resource for us to have as well. I would make a engine function where you pass it the distance and z offset, gravity and initial velocity. Mine works for mid-range values, but goes long up close and short far away. I've tried the simple one for flat ground and it does the same thing.
If you dont know what this is supposed to do, its for ballistic projectiles and setting the correct arc for making it land at a specified location.
Now it looks like from the literature I shouldnt have to add my calcarc result to the z part of the target, but if I dont then its way too low... SOMEONE must have this figured out for torque.
Thanks,
-s
If you dont know what this is supposed to do, its for ballistic projectiles and setting the correct arc for making it land at a specified location.
function AIPlayer::CalcArc(%this)
{
%x= VectorDist( %this.getPosition(), %this.attackTarget.getPosition()) ;
%y= getWord( %this.attackTarget.getPosition(),2) - getWord( %this.getPosition(),2);
%g= (1.0 * -9.81);
%v=80.0;
echo( "X:" SPC %x SPC "Y:" SPC %y);
%a = ( %g * %x *%x)/(2* %v *%v);
%b = ( -%x);
%c = ( %g * %x *%x)/(2* %v *%v) +%y;
%val = msqrt( (%b*%b) - (4 * %a * %c) );
%val2 = (( -%x + %val)/(2*%a));
%val3 = (( -%x - %val)/(2*%a));
%theta = matan1(%val2);
%theta2 = matan1(%val3);
echo( "a:" SPC %a SPC "b:" SPC %b SPC "c:" SPC %c SPC "val:" SPC %val SPC "Val2:" SPC %val2 SPC "Val3:" SPC %val3);
if( (%theta2 < %theta) )
{
%adj = %v * mSin(%theta2);
}
else
{
%adj = %v * mSin(%theta);
}
echo("Theta:" SPC %theta SPC "Theta2:" SPC %theta2 SPC " Adj:" SPC %adj);
return %adj;
}
function AIPlayer::Attack(%this)
{
%vec = %this.attackTarget.getPosition();
%z=%this.CalcArc(%this) + getWord(%vec,2);
%vec= getWord(%vec,0) SPC getWord(%vec,1) SPC %z;
echo("Aim loc:" SPC %vec);
}Now it looks like from the literature I shouldnt have to add my calcarc result to the z part of the target, but if I dont then its way too low... SOMEONE must have this figured out for torque.
Thanks,
-s
#2
EDIT: just noticed - his quadratic formula seems odd - shouldnt it be (( -%b + % val)/(2*%a));
05/07/2005 (4:04 am)
Wow, this is great. Thanks for posting this explanation. Great refresher since I havent messed wtih projectile physics in the last 3 years =-DEDIT: just noticed - his quadratic formula seems odd - shouldnt it be (( -%b + % val)/(2*%a));
#3
05/07/2005 (5:06 am)
@ Chris - You should update your profile to "Programmer - Advanced"
#4
The prblem is it seems to aim fine when they are on similar elevations - but once they cange elevations, I get crazy z values (like 29) which sends it flying over their head!
05/07/2005 (11:44 pm)
Hrm. Ok I'm having trouble implementing this function. I get the theroy behind it, but the number just dont seem... right. heres my code block://////////////////////////////////////////////////////////
//constants:
%g = -9.81;
%v = 20;
%attackerPos = VectorAdd(%attacker.getPosition(), "1 1 1");
%targetPos = %target.getPosition();
//////////////////////////////////////////////////////////
//nice to know stuff:
%y = getWord( %targetPos,2) - getWord( %attackerPos,2);
%d = VectorDist( VectorDot(%attackerPos, "1 1 0"), VectorDot(%targetPos, "1 1 0")) ;
//ax^2 + bx + c
%a = %g*%d*%d/(2*%v*%v);
%b = %d;
%c = %a - %y;
//////////////////////////////////////////////////////////
//use quadratic formula:
%discrim = msqrt( (%b*%b) - (4 * %a * %c) );
%x1 = (( -%b + %discrim)/(2*%a));
%x2 = (( -%b - %discrim)/(2*%a));
%theta1 = mAsin(%x1/ ( msqrt( 1 + %x1*%x1 )) );
%theta2 = mAsin(%x2/( msqrt( 1 + %x2*%x2 )) );//mATan(1, %x2);
//grab the largest angle, so we can see it obviously during testing
if( (%theta2 > %theta1) )
{
%theta = %theta2;
}
else
{
%theta = %theta1;
}
//////////////////////////////////////////////////////////
// theta = firing angle on z
// phi = angle to target on horizontal plane - this seems a'ok
%phi = mAtan( getWord(%targetPos, 0) - getWord(%attackerPos, 0), getWord(%targetPos, 1) - getWord(%attackerPos, 1));
%x = %v*mcos(%theta)*msin(%phi);
%y = %v*mcos(%theta)*mcos(%phi);
%z = %v*msin(%theta);
echo( "Theta:" SPC %theta SPC "1:" SPC %theta1 SPC "2:" SPC %theta2 );
echo( "X:" SPC %x SPC "Y:" SPC %y SPC "Z:" SPC %z );
echo( "A:" SPC %a SPC "B:" SPC %b SPC "C:" SPC %c );
%initVel = %x SPC %y SPC %z;The prblem is it seems to aim fine when they are on similar elevations - but once they cange elevations, I get crazy z values (like 29) which sends it flying over their head!
#5
now someone answer my datablock questions!
05/08/2005 (8:18 am)
Look at chris second equation. it assumes a height of zero at time=0. add another constant for initial height and allow the result propagate through the rest of your equations. now someone answer my datablock questions!
#6
I'm not sure about this line:
I assume you are trying to calculate the horizontal distance between %attackerPos and %targetPos. VectorDot will return a scaler, VectorDist expects two vectors. Also, the "1 1 0" vector you are using with VectorDot does not have length=1 so you are not getting the correct distance anyway.
Try using:
You will need to change the name of your '%y' variable to eg. '%z'.
Why are you using:
instead of:
You will also want to check (before doing the square root) that your discriminant is not negative. If it is, there is no angle that would cause the projectile to hit the target. Likely cause is insufficient initial velocity.
05/08/2005 (1:07 pm)
@John:I'm not sure about this line:
%d = VectorDist( VectorDot(%attackerPos, "1 1 0"), VectorDot(%targetPos, "1 1 0"));
I assume you are trying to calculate the horizontal distance between %attackerPos and %targetPos. VectorDot will return a scaler, VectorDist expects two vectors. Also, the "1 1 0" vector you are using with VectorDot does not have length=1 so you are not getting the correct distance anyway.
Try using:
%x = getWord( %targetPos,0) - getWord( %attackerPos,0); %y = getWord( %targetPos,1) - getWord( %attackerPos,1); %d = msqrt(%x*%x + %y*%y);
You will need to change the name of your '%y' variable to eg. '%z'.
Why are you using:
%theta1 = mAsin(%x1/ ( msqrt( 1 + %x1*%x1 )) );
instead of:
%theta1 = mAtan(%x1, 1);
You will also want to check (before doing the square root) that your discriminant is not negative. If it is, there is no angle that would cause the projectile to hit the target. Likely cause is insufficient initial velocity.
#7
Aha, excellant. Thats exactly what I needed. I had forgotten what dot product is actually. (blushes). Haven't had or used linear algebra in quite a while. =-)
I was using the sin ident instead of the atan x , 1 becaues i didnt realize that property of it.
However, now I know.
Thanks tons for all your work on this.
05/08/2005 (9:12 pm)
@ChrisAha, excellant. Thats exactly what I needed. I had forgotten what dot product is actually. (blushes). Haven't had or used linear algebra in quite a while. =-)
I was using the sin ident instead of the atan x , 1 becaues i didnt realize that property of it.
However, now I know.
Thanks tons for all your work on this.
#8
Did y'all get this to work, as mine works fine, at least for what I need. Glad to see others using it. I should post my new code. The major difference from what I can remember is that the dist does need to be computed on the XY plane.
05/09/2005 (5:25 pm)
Oh wow, i didnt realize this thread was alive... Did y'all get this to work, as mine works fine, at least for what I need. Glad to see others using it. I should post my new code. The major difference from what I can remember is that the dist does need to be computed on the XY plane.
#9
05/09/2005 (10:59 pm)
Yeah this above code works after the changes Chris suggested. Furthermore iI added motion tracking by just adding the targets velocity to the initialVelocity of the projectile. I can post this in full if someone wants it, though its about 3 lines changed =-)
#10
I was looking for something like this, but I had a different point of view. I thought I would have a given theta, say 45
05/15/2005 (3:53 pm)
Hi!I was looking for something like this, but I had a different point of view. I thought I would have a given theta, say 45
#11
05/15/2005 (5:36 pm)
If anyone get's something like this working, you should post it as a resource.
#12
It is certainly a better idea to choose a theta angle, then solve for initial velocity. You can make a pretty good guess at the appropriate firing angle based on the angle between source and destination positions. To account for gravity, you'd generally make the firing angle a bit larger than the angle between the two objects.
eg. If the angle between the two is 65 degrees, you might choose to fire the projectile at 75 degrees. eg.
It's then fairly straightforward to derive the equation to compute initial velocity:
[edited for small error in formula - thanks, Luis!]
05/15/2005 (6:16 pm)
Hi Luis,It is certainly a better idea to choose a theta angle, then solve for initial velocity. You can make a pretty good guess at the appropriate firing angle based on the angle between source and destination positions. To account for gravity, you'd generally make the firing angle a bit larger than the angle between the two objects.
eg. If the angle between the two is 65 degrees, you might choose to fire the projectile at 75 degrees. eg.
theta = mAtan(target.z - src.z, d); // add a little to firing angle to account for gravity theta += 0.1745;
It's then fairly straightforward to derive the equation to compute initial velocity:
////////////////////////////////////////////////////////// // calculate difference vectors %dx = getWord(%targetPos,0) - getWord(%attackerPos,0); %dy = getWord(%targetPos,1) - getWord(%attackerPos,1); %dz = getWord(%targetPos,2) - getWord(%attackerPos,2); // d = distance to target on horizontal (xy) plane %d = msqrt(%dx*%dx + %dy*%dy); // phi = angle to target on horizontal (xy) plane %phi = mAtan(%dx, %dy); ////////////////////////////////////////////////////////// // determine firing angle %theta = mAtan(%dz, %d); %theta += 0.1745; // add 10 degrees to account for gravity ////////////////////////////////////////////////////////// // determine initial speed %tanTheta = mTan(%theta); %v = msqrt(%g*%d*%d * (1 + %tanTheta*%tanTheta) / (2*(%dz - %d*%tanTheta*%tanTheta))); %vx = %v*mCos(%theta)*mSin(%phi); %vy = %v*mCos(%theta)*mCos(%phi); %vz = %v*mSin(%theta);
[edited for small error in formula - thanks, Luis!]
#13
However, you need a minimum shooting angle. If you don't use it, and your target is a few good angles below you (say it's you, 'o' , then a plain, then a slope and the enemy, 'x'):
and you use just Atan + 0.17 for the shooting angle, you will most probably shoot the floor before the slope. Anyway, that kind of targets are difficult to hit. You need a wide shooting angle.
And just a little error, isnt' it...
%v = msqrt(%g*%d*%d * (1 + %tanTheta*%tanTheta) / (2 * (%dz - %d*%tanTheta*%tanTheta)));
without that '2' the initial velocity is too high.
05/16/2005 (1:28 am)
Yes, ok, that was the idea :)However, you need a minimum shooting angle. If you don't use it, and your target is a few good angles below you (say it's you, 'o' , then a plain, then a slope and the enemy, 'x'):
O -------------------------------- ---------------------------------- ------------------------------------ X --------------------------------------------------
and you use just Atan + 0.17 for the shooting angle, you will most probably shoot the floor before the slope. Anyway, that kind of targets are difficult to hit. You need a wide shooting angle.
And just a little error, isnt' it...
%v = msqrt(%g*%d*%d * (1 + %tanTheta*%tanTheta) / (2 * (%dz - %d*%tanTheta*%tanTheta)));
without that '2' the initial velocity is too high.
#14
05/16/2005 (11:57 am)
I know there are other derivations of this general formula in game gems 3 and I'm sure elsewhere. I'll take a look this week and at least post how to solve for the initial velocity.
#15
initial velocity = ( x/ cos (theta) ) * squareroot ( grav/ ( 2 * ( x * tan(theta) - y) ) )
havent tested it, but this is what game gems claims!
-s
06/05/2005 (2:31 pm)
Ok, I know its been a while, sorry, but here's the Vi solution:initial velocity = ( x/ cos (theta) ) * squareroot ( grav/ ( 2 * ( x * tan(theta) - y) ) )
havent tested it, but this is what game gems claims!
-s
Associate Chris Robertson
The vertical location at time, t is given by the standard equation:
If the projectile is launched at an angle theta, the initial vertical velocity, u is equal to v*sin(theta). Where v is the initial speed. So:
The horizontal distance travelled, d, is (ignoring drag!) given by:
substituting for t gives:
if we multiply the last term by (sin(theta)^2 + cos(theta)^2 == 1), we get
this is just a quadratic equation of the form:
As you are already doing, use the quadratic formula to get the roots, these will give you two possible firing angles, just choose one.
The major problem I can see with your code is that when you compute the distance using VectorDist, you should ignore the Z component, as you want the XY plane distance only.
Once you have your firing angle, you need to convert it to some initial velocities: