The code for calculating the angle for target interception works, but the code for calculating the pitch needed to hit the target doesn't. When the monster fires, it shoots nearly straight up and misses me.
I know the math is right, as I tested it outside GZDoom.
Code: Select all
// Pitch calculation function
class S7_Math : actor {
/* Summary:
** Calculates the correct pitch a shooter needs to fire a gravity-affected projectile at to have it hit the target.
** Written by Chronos "phantombeta" Ouroboros. The equation were taken from Wikipedia.
**
** Arguments:
** shooterPos: The shooter's position.
** targetPos: The target's position.
** v: The projectile's speed.
** grav: The projectile's gravity multiplier.
**
** Returns:
** The pitch that the projectile will need to be fired at. Actually returns two doubles.
*/
static double, double InterceptShotPitch (Vector3 shooterPos, Vector3 targetPos, double v, double grav) {
double g = BASEGRAVITY * grav,
x = (shooterPos.xy - targetPos.xy).Length (),
y = targetPos.z - shooterPos.z;
double sq = (v*v*v*v) - g*(g*(x*x) + 2 * y * (v*v));
if (sq >= 0 && sq != double.NaN) {
double x1 = atan2 ((v*v) + sqrt (sq), g * x);
double x2 = atan2 ((v*v) - sqrt (sq), g * x);
Console.Printf ("shooter (x: %f, y: %f, z: %f)\ntarget (x: %f, y: %f, z: %f)\nx1: %f\nx2: %f\ng: %f, x: %f, y: %f",
shooterPos.x, shooterPos.y, shooterPos.z, targetPos.x, targetPos.y, targetPos.z, x1, x2, g, x, y);
return x1, x2;
} else
return double.NaN, double.NaN;
}
}
// Monster code: Target interception and pitch calculation
virtual Vector3 LeadTarget (Actor targ, double projSpeed) {
if (!target)
return (double.NaN, double.NaN, double.NaN);
Vector3 targPos = targ.pos;
targPos.z += targ.height / 2;
if (targ.vel.x != 0 || targ.vel.y != 0 || targ.vel.z != 0) { // If the target is moving, lead it.
Vector3 tempTargPos = S7_Math.CalculateInterceptShotPosition (pos, targPos, targ.vel, projSpeed);
if (targPos.x != double.NaN && targPos.y != double.NaN && targPos.z != double.NaN)
targPos = tempTargPos;
}
let marker = Spawn ("S7_PositionMarker", targPos);
A_Face (marker, 0, 0);
marker.Destroy ();
return targPos;
}
virtual double PitchCorrection (Vector3 targPos, double xyOffs, double zOffs, double projSpeed, double grav) {
double x1, x2;
[x1, x2] = S7_Math.InterceptShotPitch ((pos.x + cos (angle)*xyOffs, pos.y + sin (angle)*xyOffs, pos.z + zOffs), targPos, projSpeed, grav);
if (x1 == double.NaN && x2 == double.NaN) // If these are null, well fuck. Probably means we can't hit.
return double.NaN;
else if (x2 == double.NaN)
return x1;
return x2;
}
// Monster code: Shooting
Missile.Grenade:
TERM J 1 {
/*if (!CheckIfCloser (target, 875.0))
return ResolveState ("Missile.NoGrenade");*/
A_PlaySound ("Terminator/LauncherStart", CHAN_Weapon); // Play the launcher attack begin sound
A_FaceTarget (90, 45); // Spin to face target
return ResolveState (null);
}
TERM JJJ 1 A_FaceTarget (90, 45); // Spin to face target
TERM K 1 bright {
Vector3 targPos = LeadTarget (target, 75.0);
double newPitch = PitchCorrection (targPos, -18.0, 35.0, 75.0, 0.2);
Console.Printf ("%f", newPitch);
/*if (newPitch == double.NaN)
Console.Printf ("AAAAAAAAAAAAAA\nAAAAAAAAAAAAAA\nAAAAAAAAAAAAAA\nAAAAAAAAAAAAAA\nAAAAAAAAAAAAAA\nAAAAAAAAAAAAAA\nAAAAAAAAAAAAAA");//return ResolveState ("Missile.GrenadeStronger");*/
A_SetPitch (-newPitch);
A_PlaySound ("Terminator/GrenadeFire", CHAN_Weapon); // Play the firing sound
A_SpawnProjectile ("S7_TerminatorGrenade", 35.0, -18, 0.0, CMF_AimDirection | CMF_AbsolutePitch, pitch);
return ResolveState (null);
}
TERM KK 1 bright;
goto Missile.Grenade.End;