When dealing with 3D pathfinding, Unity's navigation workflow doesn't typically allow for characters to evade one another accurately. The NavMesh Agent component does have built-in avoidance, but agents won't factor in others when calculating their paths.
With Unity 2022.3, however, Unity introduced the AI Navigation toolset - which offer much more in the way of runtime manipulation. The steps below describe how it can be leveraged to have multiple characters properly avoiding each other when pathfinding.
- Using Unity 2022.3 or later, import the AI Navigation package from the Package Manager
- Choose AI -> Navigation in the top toolbar to open the Navigation window. For each character to involve, define a new Agent Type with that character's name.
- For each character, attach the NavMesh Agent and AC's NavMesh Agent Integration components. Set the Agent Type to the one defined for that character in step 2.
- Each character needs to traverse their own NavMesh. For each character, create a new empty GameObject and attach the NavMesh Surface compoennt. Set the Agent Type to that of the character it represents, and configure the rest of its Inspector to suit.
- We will then use a separate object, attached to each character, that carves out all NavMeshes except for the character it is attached to. For each character, create a Capsule, parent it to the character's root, and raise it up to match the character. The Mesh Renderer can be removed, but keep the Capsule Collider.
- To this Capsule, attach the NavMesh Modifier component. Set the Mode to Remove object, and the Affected Agents to match that of the character it is parented to.
- Copy/paste the code below into a C# file named Rebaker, and attach the new Rebaker component to the Capsule as well.
- In the Rebaker's Inspector, assign all of the scene's NavMesh Surface components except the one that references this character's agent.
At runtime, each capsule should then carve a circle surrounding the character out of each of the other NavMeshes, allowing other characters to pathfind around it while unaffecting their own.
Rebaker.cs:
using Unity.AI.Navigation;
using UnityEngine;
public class Rebaker : MonoBehaviour
{
public NavMeshSurface[] surfacesToRebake;
public float minRebakeDistance = 0.1f;
private Vector3 lastPosition;
private void Start ()
{
Rebake ();
}
void Update ()
{
if ((lastPosition - transform.position).sqrMagnitude >= minRebakeDistance)
{
Rebake ();
}
}
void Rebake ()
{
foreach (NavMeshSurface surface in surfacesToRebake)
{
surface.BuildNavMesh ();
}
lastPosition = transform.position;
}
}