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:
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:
Everything works as expected, the NPC now follows the Player and stops at a set distance.