NPC Follow Player in Unity 3D

NPC Follow Player in Unity 3D

by NSDG • Jul 29, 2019 • 0 Comments
194
NPC or Non-Player Character is a term used to describe the game entity that's controlled by the AI.

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

In this tutorial we will be creating a simple NPC that follows the player in Unity 3D.

So let’s begin!

Unity version used in this tutorial: Unity 2018.3.0f2 (64-bit)

Step 1: Creating a Player instance


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

  • Create new GameObject (GameObject -> Create Empty) and name it “Player”
  • Create 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 Player Object and change its position to (0, 1.64, 0)

Create new script and name it SC_CharacterController. Paste the code below inside it:

SC_CharacterController.cs
using UnityEngine;

[RequireComponent(typeof(CharacterController))]

public class SC_CharacterController : MonoBehaviour
{
    public float speed = 3.5f;
    public float jumpSpeed = 8.0f;
    public float gravity = 20.0f;
    public Camera playerCamera;
    public float lookSpeed = 3.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 / lookSpeed;
    }

    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");
            rotation.x += -Input.GetAxis("Mouse Y");
            rotation.x = Mathf.Clamp(rotation.x, -20f, 20f);
            transform.eulerAngles = new Vector2(0, rotation.y) * lookSpeed;
            playerCamera.transform.localRotation = Quaternion.Euler(rotation.x * lookSpeed, 0, 0);
        }
    }
}

  • Attach the SC_CharacterController script to Player Object and assign a child Main Camera to a Player Camera variable
  • You will notice it automatically added another component called Character Controller, change its center position to (0, 1, 0)



Step 2: Creating the NPC


  • Create new GameObject and name it “NPC
  • Create new Capsule, move it inside NPC Object and change its position to (0, 1, 0)
  • Create 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)

Now before anything else, we need to bake the NavMesh in our Scene:

  • Mark every static Object in the Scene as Navigation Static




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

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

Unity 3D NavMesh Bake

Now we can move to programming the NPC movement:

  • Assign NavMesh Agent component to NPC Object
  • Create new script and name it SC_NPCFollow
  • Attach SC_NPCFollow script to 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>();
    }

And 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 couple of 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 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:



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