Create an NPC that Follows the Player in Unity

Non-player characters or NPCs are the characters that are not controlled by a human player and instead are controlled by the scripts or the AI.

The most common task that NPCs have to do, is to follow or chase the Player.

In this tutorial, I will be showing how to make an NPC that follows the player in Unity.

Step 1: Create the Player Controller

We will create a simple Player Controller, so we can walk around and test the NPC:

  • Create a new GameObject ('GameObject' -> 'Create Empty') and name it "Player"
  • Create a new Capsule ('GameObject' -> '3D Object' -> 'Capsule'), move it inside Player Object, and change its position to (0, 1, 0)
  • Remove the Capsule Collider component from a Capsule
  • Move the Main Camera inside the Player Object and change its position to (0, 1.64, 0)
  • Create a new script, name it 'SC_CharacterController' then paste the code below inside it:

'SC_CharacterController.cs'

using UnityEngine;

[RequireComponent(typeof(CharacterController))]

public class SC_CharacterController : MonoBehaviour
{
    public float speed = 7.5f;
    public float jumpSpeed = 8.0f;
    public float gravity = 20.0f;
    public Camera playerCamera;
    public float lookSpeed = 2.0f;
    public float lookXLimit = 45.0f;

    CharacterController characterController;
    Vector3 moveDirection = Vector3.zero;
    Vector2 rotation = Vector2.zero;

    [HideInInspector]
    public bool canMove = true;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        rotation.y = transform.eulerAngles.y;
    }

    void Update()
    {
        if (characterController.isGrounded)
        {
            // We are grounded, so recalculate move direction based on axes
            Vector3 forward = transform.TransformDirection(Vector3.forward);
            Vector3 right = transform.TransformDirection(Vector3.right);
            float curSpeedX = speed * Input.GetAxis("Vertical");
            float curSpeedY = speed * Input.GetAxis("Horizontal");
            moveDirection = (forward * curSpeedX) + (right * curSpeedY);

            if (Input.GetButton("Jump"))
            {
                moveDirection.y = jumpSpeed;
            }
        }

        // Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
        // when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
        // as an acceleration (ms^-2)
        moveDirection.y -= gravity * Time.deltaTime;

        // Move the controller
        characterController.Move(moveDirection * Time.deltaTime);

        // Player and Camera rotation
        if (canMove)
        {
            rotation.y += Input.GetAxis("Mouse X") * lookSpeed;
            rotation.x += -Input.GetAxis("Mouse Y") * lookSpeed;
            rotation.x = Mathf.Clamp(rotation.x, -lookXLimit, lookXLimit);
            playerCamera.transform.localRotation = Quaternion.Euler(rotation.x, 0, 0);
            transform.eulerAngles = new Vector2(0, rotation.y);
        }
    }
}
  • Attach the 'SC_CharacterController' script to the Player Object and assign a child Main Camera to a Player Camera variable
  • You will notice it automatically added another component called Character Controller, changing its center position to (0, 1, 0)

Step 2: Create the NPC

To create an NPC, follow the steps below:

  • Create a new GameObject and name it "NPC"
  • Create a new Capsule, move it inside NPC Object, and change its position to (0, 1, 0)
  • Create a new Material and name it "npc_material"
  • Change the color of npc_material to red
  • Assign npc_material to Capsule inside NPC Object (this is just so we can distinguish NPC from the Player)

Before continuing, we need to bake the NavMesh in our Scene.

NavMesh stands for "Navigation Mesh" and is used in pathfinding to allow NPCs to navigate the level without bumping into obstacles.

To bake the NavMesh, follow the steps below:

  • Mark every static Object in the Scene as Navigation Static

  • Go to Navigation Window ('Window' -> 'AI' -> 'Navigation'), select Bake Tab then click Bake

After the NavMesh is baked, it should look something like this:

Unity 3D NavMesh Bake

Now we can move to the programming of the NPC movement:

  • Attach the 'NavMesh Agent' component to NPC Object
  • Create a new script and name it 'SC_NPCFollow'
  • Attach the 'SC_NPCFollow' script to the NPC Object
  • Open the 'SC_NPCFollow' script

First, we begin by adding a UnityEngine.AI namespace at the beginning of the script:

using UnityEngine.AI;

Then we define the necessary variables:

    //Transform that NPC has to follow
    public Transform transformToFollow;
    //NavMesh Agent variable
    NavMeshAgent agent;

In the 'void Start()' we begin by getting the NavMesh Agent component attached to this Object:

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
    }

Finally, in the 'void Update()' we instruct the NavMesh Agent to follow the Player:

    // Update is called once per frame
    void Update()
    {
        //Follow the player
        agent.destination = transformToFollow.position;
    }

Here is the final 'SC_NPCFollow.cs' script:

using UnityEngine;
using UnityEngine.AI;

public class SC_NPCFollow : MonoBehaviour
{
    //Transform that NPC has to follow
    public Transform transformToFollow;
    //NavMesh Agent variable
    NavMeshAgent agent;

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    // Update is called once per frame
    void Update()
    {
        //Follow the player
        agent.destination = transformToFollow.position;
    }
}

Fixing some issues:

Issue 1: After pressing Play, the NPC capsule hovers above the ground:

Solution: Change the Base Offset variable in NavMesh Agent to a negative value (in my case it's -0.08)

Issue 2: The NPC comes too close when following the Player:

Solution: Change the Stopping Distance in NavMesh Agent to a higher value (in my case I set it to 5)

The NPC is now ready, let's test it:

Sharp Coder Video Player

Everything works as expected, the NPC now follows the Player and stops at a set distance.

Links
Unity 6