How to make rockets follow an enemy correctly.

In our game, we have different turret types, one of which is a rocket launcher which looks like this…

Rocket Launcher, Needs another art pass…

The rocket launcher fires rockets (duh) which lock on to and track the nearest enemy.
If the target enemy dies before the rocket reaches it, the rocket looks for a new target to track.
The problem is, currently the rocket snaps towards this new vector rather than steering smoothly towards it.

The code to track our targeted enemy looks like this:

Void Update()
 {
            Vector3 dir = target.position - transform.position;
            float distanceThisFrame = speed * Time.deltaTime;


            if (dir.magnitude <= distanceThisFrame)
            {
                //we hit the target
                HitTarget();
                return;
            }
            transform.Translate(dir.normalized * distanceThisFrame, Space.World);

            //rotation
            transform.LookAt(target);
        }

Lets break it down line by line and see what’s going on.

Firstly, we get the direction vector to the target by subtracting our own position from the targets position.

Vector3 dir = target.position - transform.position;

Next, we calculate how far the rocket will move this frame.

float distanceThisFrame = speed * Time.deltaTime;

Then, we see if the rocket will move past it’s target this frame. If it does, we can say that we’ve hit it, explode the rocket, cause damage etc.

if (dir.magnitude <= distanceThisFrame)
            {
                //we hit the target
                HitTarget();
                return;
            }

If it doesn’t, we translate to the new position, in world space rather than local space and adjust our rotation if needed.

transform.Translate(dir.normalized * distanceThisFrame, Space.World);

//rotation
transform.LookAt(target);

This works perfectly fine for our use case until another turret kills our targeted enemy and the rocket selects a new target.

if (target == null)
        {
            ReTarget();
        }      

The rocket then immediately snaps its rotation to face the new targeted enemy which looks very bad indeed.

Lets re-write all of the movement and rotation code so the rocket steers towards the target and instead of calculating the distance we will travel this frame and moving there, we will let the physics system be responsible for moving our projectile and handling collisions.

Firstly, We’ll add a rigid body and a mesh collider to our rocket.

public Rigidbody rb = null;

Next, we’ll need a variable to store our rotation speed

public float rocketRotationSpeed = 500f;

In our FixedUpdate function, we can now move the rocket forward using the rigidBody component by setting its velocity

rb.velocity = transform.forward * speed;

Next, calculate the new rotation vector to our target and convert the vector into a Quaternion

Vector3 heading = target.position - transform.position;
var rotation = Quaternion.LookRotation(heading);

Lastly, we can smoothly rotate towards the target using Quaternion.RotateTowards();

rb.MoveRotation(Quaternion.RotateTowards(transform.rotation, rotation, rocketRotationSpeed * Time.deltaTime));

There is still more work to do to handle collisions which is fairly trivial.

private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.tag == "Enemy")
        {
            HitTarget();
        }
        else { Explode();
        }
    }

We now have rockets which turn convincingly and damage the target upon collision.
We could go further and add target path prediction and deviation to make the rocket fly more realistically, but I don’t really think it’s needed just yet.
If I do decide to add that, I’ll make sure to add another post about it.

Cheers.