Projectile following a parabolic trajectory to a designated point
by Jack Stone · in Technical Issues · 01/12/2014 (4:10 pm) · 3 replies
Hello,
I am trying to implement grenades in a Tactical Squad-based game. I am selecting AIPlayers using a point and click interface, and right clicking on a point in the world, which I want to be the destination of the grenade.
However, I am not sure how to provide and initial vector to the projectile in order to get it to land at or near the target point while still travelling in a parabolic arc (I could just use a conventional straight-shooting projectile, but this would look horrible).
I found some excellent information here:
http://www.blitzbasic.com/Community/posts.php?topic=73320
I hope noone will mine me posting a link from a rival game engine! But the equations there seem to provide the correct angle to hit a target if the muzzle velocity is known. I can simply hardcode the muzzle velocity, so this should work.
However, I first need to be able to create a projectile which is offset from the muzzle vector by a given angle. I thought this was simple, I have done rotations before, but it seems I can only rotate my vectors about the z axis. I am using this function:
To rotate, but the problem is that it only works when the muzzle vector is pointing in a specific direction. I think the problem is that I need to rotate about an arbitrary axis? As opposed to a fixed axis?
I don't know how exactly to do this. I came accross a few c++ examples for other engines and libraries, but nothing I can replicate in script.
Is there an easier way to fire a projecile along a parabolic path, landing at a fixed point?
Thanks for any help!
I am trying to implement grenades in a Tactical Squad-based game. I am selecting AIPlayers using a point and click interface, and right clicking on a point in the world, which I want to be the destination of the grenade.
However, I am not sure how to provide and initial vector to the projectile in order to get it to land at or near the target point while still travelling in a parabolic arc (I could just use a conventional straight-shooting projectile, but this would look horrible).
I found some excellent information here:
http://www.blitzbasic.com/Community/posts.php?topic=73320
I hope noone will mine me posting a link from a rival game engine! But the equations there seem to provide the correct angle to hit a target if the muzzle velocity is known. I can simply hardcode the muzzle velocity, so this should work.
However, I first need to be able to create a projectile which is offset from the muzzle vector by a given angle. I thought this was simple, I have done rotations before, but it seems I can only rotate my vectors about the z axis. I am using this function:
function RotateVectorOnY(%Vec,%angle){
%X = GetWord(%Vec,0);
%Y = GetWord(%Vec,1);
%Z = GetWord(%Vec,2);
%rdAngle=mDegToRad(%angle);
%rX = (%X*mCos(%rdAngle))+(%Z*mSin(%rdAngle));
%rY = %Y;
%rZ = (%X*mSin(%rdAngle))-(%Z*mCos(%rdAngle));
return %rX SPC %rY SPC %rZ;
}To rotate, but the problem is that it only works when the muzzle vector is pointing in a specific direction. I think the problem is that I need to rotate about an arbitrary axis? As opposed to a fixed axis?
I don't know how exactly to do this. I came accross a few c++ examples for other engines and libraries, but nothing I can replicate in script.
Is there an easier way to fire a projecile along a parabolic path, landing at a fixed point?
Thanks for any help!
#2
It's a very clever way of doing it actually, aiming at a point above the target, and letting the grenade fall onto the target? That looks much simpler than what I was trying to do with rotating the vector, but it accomplishes the same thing.
In case anyone else is interested, this is my full throw grenade function:
Once again, thanks Richard!
01/12/2014 (9:30 pm)
Richard, thank you! That's fantastic, your function worked great!It's a very clever way of doing it actually, aiming at a point above the target, and letting the grenade fall onto the target? That looks much simpler than what I was trying to do with rotating the vector, but it accomplishes the same thing.
In case anyone else is interested, this is my full throw grenade function:
function squadthrowsmokegrenade(%obj,%location){
echo("Squadthrowsmokegrenade: " @ %obj);
%projectile = SmokegrenadeProjectile;
%muzzleVector = %obj.getMuzzleVector(0);
//I modified Richard's function slightly so that it's not a method of AIPLayer:
%zoffset = getballisticaimpos(%obj,%location,%projectile.muzzleVelocity,1,1);
//%zoffset is now the height above the target where we want to aim. //Target is already facing the target after using setaimlocation()
//Create a new vector with the z component set to %zoffset: (I could //have overwritten %location here, but I needed it somewhere else)
%tst = setword(%location,2,%zoffset);
//Now, grab a vector from the muzzle position to the target:
%ft = vectorsub(%obj.getPosition(),%tst);
//Normalise:
%ft = vectornormalize(%ft);
//And scale with the muzzlevelocity:
%ft = vectorscale(%ft,%projectile.muzzleVelocity);
//For some odd reason, my projectile was being thrown in the wrong //direction on the x and y axes. These lines flip those axes. There is //probably a better way of doing this:
%xn = getword(%ft,0);
%yn = getword(%ft,1);
%ft = setword(%ft,0,(%xn*-1));
%ft = setword(%ft,1,(%yn*-1));
// FInally, create the projectile object:
%p = new (Projectile)()
{
dataBlock = %projectile;
initialVelocity = %ft;
initialPosition = %obj.getMuzzlePoint(0);
sourceObject = %obj;
sourceSlot = 1;
client = %obj.client;
sourceClass = %obj.getClassName();
};
MissionCleanup.add(%p);
}Once again, thanks Richard!
#3
01/15/2014 (7:49 pm)
Thank Bryce - I got it from him... lol
Torque Owner Richard Ranft
Roostertail Games
/// <summary> /// This function calculates a firing offset for ballistic projectiles. Thanks to /// Bryce for the vast majority of this function - /// https://www.garagegames.com/community/resources/view/19739 /// <summary> /// <param name="pos">The target position.</param> /// <param name="roundVel">The muzzle velocity of the projectile.</param> /// <param name="mortarAim">True to use high arc aim, false to use flat arc aim.</param> /// <param name="gMod">The amount of gravity to apply to the projectile.</param> /// <return>Returns the z axis aim offset position - or how high above the target to aim.</return> function AIPlayer::GetBallisticAimPos(%this, %pos, %roundVel, %mortarAim, %gMod) { %posFlat = %pos; %thisPos = %this.getPosition(); %posFlat.z = %thisPos.z; %x = VectorDist(%thisPos, %posFlat); %y = %pos.z - %thisPos.z; //error("X delta: " @ %x @ " -- Y delta: " @ %y); %g = 9.82 * %gMod; %r1 = mSqrt(mPow(%roundVel,4.0) - %g * (%g * (%x * %x) + ((%y / 4) * (%roundVel * %roundVel)))); if (%r1 $= "-1.#IND") // If not a real number, it's not possible to hit %pos, return -1 return -1; %a1 = ((%roundVel*%roundVel) - %r1) / (%g * %x); %a1 = mASin(%a1 / mSqrt((%a1 * %a1) + 1)); %angleOfReach = mRadToDeg(%a1); if (%mortarAim) %angleOfReach = 90 - %angleOfReach; //error("Angle of reach is " @ %angleOfReach); %offsetHeight = mTan(mDegToRad(%angleOfReach)) * %x; //error(%this @ ": aim offset for gravity = " @ %offsetHeight); return %offsetHeight; }It lets the AIPlayer handle the left/right aim and calculates a z offset for the muzzle to get the projectile (in this case a grenade) from A to B.I had it set up so that if it couldn't hit the point it was aiming for it would move closer and check again.
Moving this into the engine makes it a lot faster.