Trying to implement proportional navigation into Unity using C#

Viewed 143

I tried using the equation for proportional navigation found in this wiki article but when I attempted to implement it in game, the missile often goes off in some direction opposite of my target.

I am not sure if this has to do with the way I normalized the acceleration to give it a maximum velocity, the precision of the coordinates, or my calculations but I have not been able to find the root of the issue.

If anyone could help it would be greatly appreciated.

Here is my code

public class Missile : MonoBehaviour
{

    Target target;
    public Transform targetTransform;
    public float speed = 5;
    public float propCon = 3;
    Vector3 lastPos;
    Vector3 miLastPos;
    Vector3 velocity;

    void Start()
    {
        target = FindObjectOfType<Target>();
       lastPos = targetTransform.position; 
       miLastPos = transform.position;
    }

    void Update()
    {
        Vector3 targetVelocity = (targetTransform.position - lastPos) / Time.deltaTime;
        Vector3 miVelocity = (transform.position - miLastPos) / Time.deltaTime;
       
        lastPos = targetTransform.position;
        miLastPos = transform.position;

        Vector3 range = targetTransform.position - transform.position;
        Vector3 relVelocity = targetVelocity - miVelocity;
        Vector3 rotVector = Vector3.Cross(range, relVelocity) / Vector3.Dot(range, range);
        Vector3 accNormal = propCon * Vector3.Cross(relVelocity, rotVector);
        Vector3 directionToTarget = accNormal.normalized;

        float distanceToTarget = range.magnitude;

        print ($"TV is: {targetVelocity} and lastPos {lastPos}\nmiVelocity is: {miVelocity} miPosition is: {miLastPos}");
        print ($"rotVector: {rotVector} and accNormal: {accNormal}\nrange: {range} and relVelocity: {relVelocity}");
        print ($"cross: {Vector3.Cross(range, relVelocity)} and dot: {Vector3.Dot(range, range)}");


        if (velocity.magnitude < speed)
        {
            velocity += (speed/10*directionToTarget);
        }

        if (distanceToTarget > 0.1f)
        {
            transform.Translate (velocity*Time.deltaTime);
        }
    }
}
1 Answers

Assuming the rest of the calculation is correct (seems so at first glance comparing to the article you linked) I think the issues comes down to

transform.Translate(velocity * Time.deltaTime);

Note that Transform.translate by default uses local space. You are however working with world space vectors. If your missiles are anyhow rotated then your coordinate systems do not match anymore.

If relativeTo is left out or set to Space.Self the movement is applied relative to the transform's local axes. (the x, y and z axes shown when selecting the object inside the Scene View [addition by me: and the gizmos are set to Local].) If relativeTo is Space.World the movement is applied relative to the world coordinate system.

I think in general you rather want to use

transform.Translate (velocity * Time.deltaTime, Space.World);

or also simply

transform.position += velocity * Time.deltaTime;

and then I would probably do this

miLastPos = transform.position;

after moving the object so the calculation should be more precise and not be based on the last frames delta movement.

Related