So the player can move to the desired destination, we will used Unity's built in navigation mesh (NavMesh).
Setting it up is pretty simple:
- Install "AI Navigation" package from Package Manager (if you don't already have it installed). You can do this by opening Window > Package Manager. Choose "Unity Registry" and search for "AI Navigation".
- In scene, create a Plane, which will be ground (Right click on Hiearchy > 3D Object > Plane). Make sure that Plane has a collider, so our player won't fall through later.
- Right click on your Plane and choose AI > NavMesh Surface. This will create a child object with NavMeshSurface component.
- Bake the NavMesh by clicking "Bake" in the "NavMeshSurface" component.
Generated NavMesh:
In this example I used an asset from Synty Studios called "POLYGON - Explorer Kit". You can purchase this asset here. But you can use any other model you have available (it has to be properly rigged for animations to work).
We want 3 types of animations for our player: idle, walking and runnning. You can get these animation from Mixamo or you can use an asset from Unity Asset Store. I used Basic Motions FREE.
- Create a new Animator Controller in Project > Create > Animator Controller and name it "PlayerAnimatorController".
- Open the Animator window by double clicking on the Animator Controller.
- Create a new Blend Tree by right clicking in the Animator window and choosing Create State > From New Blend Tree. Name it "Locomotion".
- In the Blend Tree, create 3 motion fields and name them "Idle", "Walk" and "Run".
- Drag and drop the animations you want to use for each motion field. For "Idle" I used "Idle" animation, for "Walk" I used "Walk" animation and for "Run" I used "Run" animation.
- Set the "Threshold" values for each motion field. For "Idle" set it to 0, for "Walk" set it to 3 and for "Run" set it to 5. These tresholds will be used to determine which animation to play based on the player's speed.
- Rename the "Blend" parameter to "Speed" and set its default value to 0.
- Make sure you assign this Animator Controller to your player's Animator component.
We already generated a NavMesh. But for our player to be able to move on it, we need to add a NavMesh Agent component to it. This component will allow us to move the player to a desired destination on the NavMesh. You just have to add the NavMesh Agent component to your player's game object.
Now we need to create a script that will control our player. Create a new C# script called "PlayerController" and attach it to your player's game object.
In this script we will check for mouse/touch clicks and move the player to the clicked position. We will also update the "Speed" parameter of the Animator component, so the correct animation is played. We will take the value from current speed of the NavMesh Agent.
Open the script and add the following code:
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(Animator))]
public class PlayerController : MonoBehaviour
{
private NavMeshAgent navMeshAgent;
private Animator animator;
private void Start()
{
navMeshAgent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}
private void Update()
{
// Update the speed parameter of the animator for the blend tree
animator.SetFloat("Speed", navMeshAgent.velocity.magnitude);
if (Input.mousePresent)
{
HandleMouseClick();
}
else if (Input.touchSupported)
{
HandleTouch();
}
}
private void HandleMouseClick()
{
if (Input.GetMouseButtonDown(0))
{
MovePlayerToPosition(Input.mousePosition);
}
}
private void HandleTouch()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved)
{
MovePlayerToPosition(touch.position);
}
}
}
private void MovePlayerToPosition(Vector3 position)
{
Ray ray = Camera.main.ScreenPointToRay(position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// Check if the touched point is on the ground
// Add a new Tag called "Ground" and assign it to your ground object
if (hit.collider.CompareTag("Ground"))
{
navMeshAgent.SetDestination(hit.point);
}
}
}
}
Now we need to setup the camera to follow the player. We will use the Cinemachine package for this. You can install it from the Package Manager (Window > Package Manager).
- Choose your "MainCamera" and add the Cinemachine Brain component to it.
- Create a new Cinemachine Virtual Camera by right clicking in the Hierarchy and choosing Cinemachine > Virtual Camera. Name it "PlayerFollowCamera".
- Assign player's game object to the "Follow" and "Look At" field of the Cinemachine Virtual Camera component.
- Set "Body" to "Transposer" and "Binding Mode" to "World Space".
- Play with "Follow Offset". In my case, the best was to set it to (-0.4, 12, -13).