I need help to debug my projectile launch vector finding code.

Hi, I have this code:

public Vector3 GetLaunchVector(Vector3 startPos, Vector3 endPos, float vel, float g)
    {
        var offset = endPos - startPos;

        var d = Mathf.Sqrt(offset.x * offset.x + offset.z * offset.z);
        var h = offset.y;
        offset.y = 0;

        float vel2 = vel * vel;
        float vel4 = vel * vel * vel * vel;
        float d2 = d * d;
       
        var theta = Mathf.Atan2(vel2 - Mathf.Sqrt(vel4 - g*(g*d2+2*h*vel2)), g * d);
       
        var rad = theta*Mathf.Deg2Rad;

        var dir = offset.normalized;
       
        Vector3.RotateTowards(dir, Vector3.up, rad, 1f);
       
        return dir;
    }

Which works with my projectile constructor (I’ll do pooling later)

ProjectileBase newProjectile =
            Instantiate(projectilePrefab, shootPoint.position, Quaternion.LookRotation(dir));
        newProjectile.Shoot(character);

to lob a projectile to hit a target in 3d space, as based on wikipedia and this thread , and it faces two major issues. First, assuming the point can be reached given the velocity and gravity given, my usage of Vector3.RotateTowards is incorrect, and as of right now I just get out whatever I put in to it. My intention with the line is to add the vertical component to my launch vector, because the formula to get theta works in 2d, I had to separate the x/z direction out and so this is my attempt to add the x/z direction back in. What could I use to accomplish this?

After that, if my target is out of range, then theta will evaluate to NaN. Is there a reasonably fast way to calculate the trajectory that will get me as close as possible to the target point in this case? Thanks!

I did this with a gun turret that had traverse and elevation. Wrote it up here:

Turret aiming/rotating:

Not sure if that will suffice… see the caveat about differences in Y, but it gets pretty close.

Thanks! From your code I was able to figure out how to translate the angles into something that my code can use, now I just need to figure out how to handle when the target is out of range.

public Quaternion GetLaunchVector(Vector3 startPos, Vector3 endPos, float vel, float g)
    {
        var offset = endPos - startPos;

        float targetYaw = Mathf.Atan2(offset.x, offset.z) * Mathf.Rad2Deg;
       
        var d = Mathf.Sqrt(offset.x * offset.x + offset.z * offset.z);
        var h = offset.y;
        offset.y = 0;

        float vel2 = vel * vel;
        float vel4 = vel * vel * vel * vel;
        float d2 = d * d;
       
        var theta1 = Mathf.Atan2(vel2 - Mathf.Sqrt(vel4 + g*(g*d2+2*h*vel2)), g * d) * Mathf.Rad2Deg;
        var theta2 = Mathf.Atan2(vel2 + Mathf.Sqrt(vel4 + g*(g*d2+2*h*vel2)), g * d) * Mathf.Rad2Deg;

        // I wanna lob the grenades high so the player can run under them. Use the highest launch angle.
        var theta = Mathf.Max(theta1, theta2);

        var quat = Quaternion.Euler(-theta, targetYaw, 0);

        return quat;
    }

The formula gets NaN when there is no solution and that of course breaks the launcher. I can listen for this case, but I don’t know how to calculate the closest angle.

I jumped to conclusions, the formula actually does do its best to reach targets out of range. I misunderstood the formula (I’m signed on for physics next semester) so I guess I am good to go :slight_smile: .

1 Like

Well the NaN is likely from your Sqrt input going negative… so put that hairy term into a variable and check it first.

IMNSHO, you really should put vel4 + g*(g*d2+2*h*vel2) into its own temporary variable… the compiler is smart enough that you can do one step per line and often the compiler will make you even faster code than the horribly long lines 15 and 16 above.

Not only that, but you’ll still be able to read and understand it two weeks from now!

1 Like

I like the thing about readability. I was wrong about the source of the NaN. I don’t get them anymore, so I think I am done with this script for now, other than doing that readability fix you suggested.