How to plot intercept position with moving target (for guided missile)

Hey guys, I’ve been working on a missile script to make them home in on a target by estimating the intercept position every update and pointing them towards that location. Known defects/improvements are:

  1. Only the target’s current velocity is taken into account. There is no prediction of turns or acceleration.
  2. I also don’t take into account the missile’s own acceleration, which is known.

My missile, with this script, will hit the ship if the ship is completely stationary. It will always arrive behind the ship if the ship is moving at all, even at a slow, constant vector. It then spins around, decelerates, accelerates back at the ship, and again arriving behind the ship. Given the way my script is written and not taking into account the missile’s acceleration, I’d expect to at least strike in front of the slowly moving ship due to assumed ETA always being faster than anticipated. So, here’s my intercept method - can anyone take a look and see where I went wrong? I took calculus ~10yrs ago, so this is some mathematical stretching for me :p.

    public void intercept(GameObject target, GameObject interceptor)
    {
        // 1) Find time for interceptor to reach target's current position: distance/speed
        float interceptTime = Vector3.Distance(target.transform.position, interceptor.transform.position)/interceptor.GetComponent<Rigidbody>().velocity.magnitude;

        // 2) Loop steps 2 & 3 until oldInterceptPosition and newInterceptPosition differ by < .5m
        Vector3 oldInterceptPosition = target.transform.position + (interceptor.GetComponent<Rigidbody>().velocity * interceptTime);
        Vector3 newInterceptPosition;
        float diff = 100;
        int count = 0; //<- added tripwire so Unity didn't infi-loop in here. It never reaches diff < .5f apparently
        do
        {
            // 2.1) Find time for interceptor to reach target's newly predicted position
            interceptTime = Vector3.Distance(oldInterceptPosition, interceptor.transform.position) / interceptor.GetComponent<Rigidbody>().velocity.magnitude;
        
            // 2.2) Find the position target will move to during time of interception.
            newInterceptPosition = target.transform.position + (interceptor.GetComponent<Rigidbody>().velocity * interceptTime);

            // 2.3) Check the difference in distances between old and new positions
            diff = Vector3.Distance(oldInterceptPosition, newInterceptPosition);
            count++;
        } while (diff > .5f && count < 20);

        // 3) Slerp towards the estimate of intercept position
        if (newInterceptPosition - transform.position != Vector3.zero)
        {
            Quaternion rotation = Quaternion.LookRotation(newInterceptPosition - transform.position);
            float damping = 100;
            interceptor.transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * damping);
        }
    }

No need for all that with a homing missile.

I have homing missiles that do no prediction. They hit accurately. Not sure why you are doing all that extra calculation. makes no sense. If the missile wasnt tracking (like a bullet). sure it would make sense.

If you really want to get into it, this is how the bullet projection is done.

http://wiki.unity3d.com/index.php/Calculating_Lead_For_Projectiles

Maybe the reason for using all the calculations is to be able to also have the homing missiles miss their target? Be it a decoy or a failure.

It all depends on the case really. At least the code is interesting to read hah! :slight_smile:

Well, for whatever reason, just going with the “1) aim at the target 2) add thrust” loop wasn’t working. Had almost the exact same result as always ending up behind the moving target. That said, yes, I do want the missiles to be able to miss the target based on fancy flying :).

Perhaps that’s a better question for me to ask right now - why don’t my simple homing missiles hit a moving, non-accelerating, target? During Update() I was running:

this.transform.rotation = Quaternion.LookRotation(target.transform.position - this.transform.position);

And during FixedUpdate() I was running:

if (this.GetComponent<Rigidbody>().velocity.magnitude < 500)
        {
            this.GetComponent<Rigidbody>().AddRelativeForce(Vector3.forward * Time.fixedDeltaTime * 1000, ForceMode.Force);
        }

Haha, thanks! That’s what I was going for, interesting code… :P.

I’m not able to tell you based on just the code, when I get home I’ll try this code and see if I can get it to work for you :slight_smile: your subject got me very much intrigued to try myself haha.

Well so far all I came up with was doing it in Update() with Vector3.MoveTowards();

using UnityEngine;

public class HomingMissile : MonoBehaviour {
    public GameObject target;
    public float missileSpeed = 50f;

    [SerializeField]
    private float _distanceFromTarget;

    void Update()
    {
        _distanceFromTarget = Vector3.Distance(this.transform.position, target.transform.position);
        float step = missileSpeed * Time.deltaTime;

        if(target != null)
        {
            this.transform.rotation = Quaternion.LookRotation(target.transform.position - this.transform.position);
            this.transform.position = Vector3.MoveTowards(this.transform.position, target.transform.position, step);
        }
    }
}

I had the same issue with the missile just ending up missing the target at its rear and then taking too much time to turn back around and gain enough momentum to go after the target again. It happens everytime it gets close to the target.

I’m sure real homing missiles however have a system that checks how close it is to its target and adjusts maybe its speed or trajectory to make sure it will intercept the target properly.

I did a quick search on Google and came up with a nice quote from a Wiki page:

Maybe either of the pages can help us achieve our goal? haha :wink:

This is my missile code.

Transform _transform;
Rigidbody _rigidbody;

Transform CurrentTarget;
float CurrentFuel = 5;
float TrackingRotation = 5;
bool IsScrambled = false;

void Start()
{
  _transform = transform;
  _rigidbody = GetComponent<Rigidbody>();
}

void FixedUpdate()
    {
      
          
            if(CurrentFuel> 0f)
            {
                //locks onto the target
                if(CurrentTarget != null && !IsScrambled)
                {
                    Vector3 TargetLocation =  CurrentTarget.position - _transform.position; 
                    Quaternion targetRotation = Quaternion.LookRotation(TargetLocation);

                    _rigidBody.MoveRotation(Quaternion.RotateTowards(_rigidBody.rotation, targetRotation, TrackingRotation));
                }
                else {
                     //handle scrambled behaviour...
                }
                              
                _rigidBody.velocity = _transform.forward * velocity;
            }
            else {
                _rigidBody.drag = 0.01f;
                _rigidBody.useGravity = true;
            }

           CurrentFuel -= Time.deltaTime;
    }

Nice and simple code :slight_smile: so you don’t have the issue of missing targets etc? Also when for instance the target makes a sharp turn and accelerates?

I see the same behavior using your code as my simple “fly towards” approach. It hits a stationary target, but will never hit a moving target.

You can see the projectiles in a video of inferno in my sig. Hits moving targets fine.

You can make the missile miss by having a slow turn rate. Obviously the higher the turn rate, the less chance you have of getting away. Also speed of missile comes into play there. If the missile is too fast and turns too slow, likely to miss a fast target.

I found the problem! It was how I was moving the missile. I was using

this.GetComponent<Rigidbody>().AddRelativeForce(Vector3.forward * Time.fixedDeltaTime * 1000, ForceMode.Acceleration);

instead of

_rigidBody.velocity = transform.forward * 100;

Apparently dealing with force on a RB missile will ensure they always miss, due to not correcting for inertia. I didn’t think it’d cause enough discrepancy between desired and actual path, but it does. If I want to go back to a thrust-based system I’ll have to correct for my current momentum.

Im surprised that was the problem.

I found velocity was the best approach to controlling missiles though.

Yeah, same, which is why I never bothered to try it until it was obviously the last thing I could try…sigh, lol. Thanks for the help, both of you!

Yep like it says on that wiki page I linked you’ll have to calculate the proper intercept path for the missile. Trying to do it at the moment just for fun, too bad I suck at math :slight_smile: what better than to take such a difficult thing to pain myself in the evening haha.

Prediction for a missile should be relatively easy. If you want to give it a bit of lead…

psudo code…

distanceOffset = Clamp(100 / distance, 0, 1);
target.forward * target.speed * distanceOffset;

Wow that was quick. To be honest I would’ve never thought of it that easy haha. Like I said I’m no math king haha. Was literally trying to recreate https://en.wikipedia.org/wiki/Proportional_navigation

Heh, tha’ts relatively simple. The fun is when you want to make a bullet hit a moving target. Combination of that first link + angle of reach calculation.

Now you’re just making me jealous with your wisdom haha. :stuck_out_tongue: Do you maybe know a link or tutorial somewhere on how to read those mathmatical formulas like on that Wiki link I gave? I’ll dive into my Math 101 book from pre-school again… :face_with_spiral_eyes: