I was trying to play around with projectile motion to make a 100% accurate projectile that follows a parabolic trajectory (basically like fireballs in doom 3), changing its pitch and velocity depending on the target's distance.
I came up with this function here, that is working wonderfully, except for when the target is closer than the maximum projectile range at maxpitch and higher than the projectile spawn pos.
Code: Select all
action void A_SpawnParabolicProj(class<actor> missiletype, double spawnheight, double spawnofs_xy = 0, double angle = 0, double maxpitch = 30, double projgravity = 0.25, bool veladjust = false, int ptr = AAPTR_TARGET) {
let ref = GetPointer(ptr); //get the set actor pointer
if(!ref || (ref && ref.Health < 1)) //if there's no victim or it's dead
return; //do nothing;
double v = GetDefaultSpeed(missiletype); //get the projectile speed
double d = Distance2D(ref); //get the distance from the victim without accounting for the altitude difference
double g = projgravity; //set the projectile's gravity with the function itself
double h = ref.pos.z + ref.height / 2.0 - self.pos.z - spawnheight; //get the height difference between the victim's center and the projectile spawn point
double k = -h; //height difference between the projectile spawn point and the victim's center
double p; //pitch
//double a = -PitchTo(ref, spawnheight - height/2, 0); //pitch from projectile spawn height and the victim center (not used)
if(maxpitch > 90.0) //if the maximum pitch exeeds 90°
maxpitch = 90.0; //set it to 90°
else if(maxpitch < 0)
maxpitch = 30.0;
double vx = v * cos(maxpitch); //horizontal velocity
double vy = v * sin(maxpitch); //vertical velocity
double b = sin(2 * (maxpitch)); //velocity component
if(b == 0)
g = 0.0;
//double t = (vy + sqrt(vy**2 + 2 * g * k)) / g; //flight time (not used)
//double r = vx * t; //maximum range (not used)
if(maxpitch != 0) {
if(veladjust && b != 0) //if the projectile shouldn't have a range limit
v = max(sqrt(d * g / b), v); // (should) adjust the projectile's velocity to be able to reach the victim
p = atan((v**2.0 - sqrt(v**4.0 - g * (g * (d**2.0) + 2.0 * h * (v**2.0)))) / (g * d)); //calculate the pitch according to every parameter and never let it exceed the maximum pitch
}
else
p = 0;
let bal = A_SpawnProjectile(missiletype, spawnheight, spawnofs_xy, angle, CMF_CHECKTARGETDEAD|CMF_ABSOLUTEPITCH, -p, ptr); //shoot the projectile with the proper parameters
if(bal) { //if the spawn was succesful
bal.gravity = g; //set the projectile's gravity (this is here to avoid conflicts with changes in the gravity property of the projectile, which becomes useless)
bal.bNOGRAVITY = false; //set the gravity, in case the projectile doesn't have it
if(veladjust) //if the velocity needs to be adjusted
bal.Vel3DFromAngle(v, bal.angle, -p); //set the correct velocity
}
}
if someone could explain to me how to achieve that or if you know some example, that would be really appreciated!