Skip to content
Learni
Voir tous les tutoriels
Unity

Comment implémenter NavMesh pour l'IA dans Unity 2026

Read in English

Introduction

NavMesh, ou Navigation Mesh, est le système de navigation pathfinding d'Unity, essentiel pour simuler des comportements IA réalistes dans les jeux 3D. Imaginez une horde d'ennemis contournant intelligemment vos barricades ou un PNJ rejoignant un point précis sans traverser les murs : c'est NavMesh qui rend cela possible en générant une maillage de navigation à partir de votre géométrie scène.

En 2026, avec Unity 2023 LTS et ses optimisations AI Navigation 2.0, NavMesh gère les mondes ouverts dynamiques, les obstacles en temps réel et l'évitement mutuel des agents. Ce tutoriel intermédiaire vous guide pas à pas : du baking initial aux scripts avancés pour multi-agents. Pourquoi c'est crucial ? Sans NavMesh, votre IA patine ou clippe ; avec, elle semble vivante. À la fin, vous déployez une scène complète avec 10 agents évitant obstacles et compagnons. Temps estimé : 45 min. Prêt à booster votre gameplay ?

Prérequis

  • Unity 2023.2 LTS ou supérieur (téléchargeable via Unity Hub).
  • Connaissances de base en C# et composants Unity (Transform, Update()).
  • Une scène 3D simple : sol plat (Cube scalé), murs (Cubes), éclairage.
  • Package AI Navigation activé (Window > Package Manager > Unity Registry > AI Navigation).

Étape 1 : Configurer et Baker la NavMesh de base

Ouvrez Window > AI > Navigation pour afficher la fenêtre Navigation.

  1. Sélectionnez votre sol : Navigation > Static > Navigation Static (cocher pour inclure dans le bake).
  2. Ajoutez NavMesh Surface (GameObject > AI > NavMesh Surface) sur un GameObject vide 'NavMeshHolder'.
  3. Dans l'inspecteur NavMesh Surface :
- Agent Type : Humanoid (rayon 0.5m, hauteur 2m). - Collect Objects : All. - Cliquez Bake : une surface bleue apparaît (visualisez en Scene view > Shaders > NavMesh).

Analogie : Le bake est comme une carte routière générée à partir de votre ville (géométrie). Testez en ajoutant un Capsule avec NavMesh Agent : il glisse maintenant intelligemment !

Script agent simple vers cible fixe

Assets/Scripts/SimpleNavAgent.cs
using UnityEngine;
using UnityEngine.AI;

public class SimpleNavAgent : MonoBehaviour
{
    [SerializeField] private Transform target;
    private NavMeshAgent agent;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        if (target == null)
        {
            Debug.LogError("Assignez une cible dans l'inspecteur !");
            return;
        }
        agent.SetDestination(target.position);
    }

    void Update()
    {
        // Arrêt si arrivé (distance < 0.5m)
        if (!agent.pathPending && agent.remainingDistance < 0.5f)
        {
            agent.ResetPath();
        }
    }
}

Ce script complet assigne un NavMeshAgent à un GameObject (Capsule) et le dirige vers une Transform cible fixe. Il gère l'arrivée en resetant le path pour éviter les boucles infinies. Piège : Oubliez le GetComponent et l'agent patine ; toujours vérifier target != null en prod.

Étape 2 : Navigation interactive (clic souris)

Pour un contrôle joueur : ajoutez un Camera en vue TPS/FPS. Le clic souris définit la destination.

Améliorations bake : Augmentez Voxel Size à 0.3 pour précision, Max Slope à 45° pour ramps. Re-bakez.

Test : Lancez Play, cliquez au sol – l'agent suit le chemin optimal, évitant murs. Visualisez le path en vert (Gizmos > Show NavMesh).

Contrôleur joueur avec clic destination

Assets/Scripts/PlayerNavController.cs
using UnityEngine;
using UnityEngine.AI;

public class PlayerNavController : MonoBehaviour
{
    [SerializeField] private Camera playerCamera;
    [SerializeField] private LayerMask groundLayer = 1 << 6; // Layer 'Ground'
    private NavMeshAgent agent;
    private RaycastHit hit;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        if (playerCamera == null) playerCamera = Camera.main;
        agent.updateRotation = false; // Rotation manuelle
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = playerCamera.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit, 100f, groundLayer))
            {
                NavMeshHit navHit;
                if (NavMesh.SamplePosition(hit.point, out navHit, 1.0f, -1))
                {
                    agent.SetDestination(navHit.position);
                }
            }
        }
    }
}

Ce contrôleur raycast le clic souris sur le layer Ground, sample la position NavMesh valide (évite bords invalides) et set la destination. Utilisez NavMesh.SamplePosition pour fiabilité. Piège : Sans layerMask, clics traversent tout ; assignez Layer 6 à votre sol.

Étape 3 : Obstacles dynamiques avec NavMeshObstacle

Pour caisses mobiles : Ajoutez NavMeshObstacle (GameObject > AI > NavMesh Obstacle) sur un Cube ennemi.

  • Shape : Box, Carve : true (creuse le NavMesh en runtime).
  • Move Threshold : 0.5m pour updates.
Les agents contournent instantanément. Pour toggle : script ci-dessous.

Script toggle obstacle dynamique

Assets/Scripts/DynamicObstacle.cs
using UnityEngine;
using UnityEngine.AI;

public class DynamicObstacle : MonoBehaviour
{
    private NavMeshObstacle obstacle;
    [SerializeField] private float moveSpeed = 2f;
    [SerializeField] private Vector3 patrolPoint;

    void Start()
    {
        obstacle = GetComponent<NavMeshObstacle>();
        patrolPoint = new Vector3(5f, 0.5f, 5f); // Point patrol
    }

    void Update()
    {
        // Mouvement simple patrol
        transform.position = Vector3.MoveTowards(transform.position, patrolPoint, moveSpeed * Time.deltaTime);

        // Toggle carve si vitesse > seuil
        if (obstacle.velocity.magnitude > 0.1f)
        {
            obstacle.carveOnlyStationary = false;
        }
        else
        {
            obstacle.carveOnlyStationary = true;
        }
    }
}

Ce script anime un obstacle en patrol, active Carve en mouvement pour percer le NavMesh dynamiquement. Velocity check optimise perf. Piège : Sans carveOnlyStationary, CPU spike ; testez avec 20+ obstacles.

Étape 4 : Évitement multi-agents

Dupliquez 5 agents. Dans Navigation window > Agents > Humanoid > Avoidance Priority : 50 (moyen).

Obstacle Avoidance Type : High Quality Obstacle Avoidance.

Les agents se poussent mutuellement sans collision physique. Boostez avec script IA random.

IA avec destinations random + avoidance

Assets/Scripts/AIAgentRandom.cs
using UnityEngine;
using UnityEngine.AI;

public class AIAgentRandom : MonoBehaviour
{
    [SerializeField] private float patrolRadius = 10f;
    [SerializeField] private float waitTime = 3f;
    private NavMeshAgent agent;
    private Vector3 startPos;
    private float waitTimer;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        agent.avoidancePriority = Random.Range(0, 99);
        startPos = transform.position;
        SetRandomDestination();
    }

    void Update()
    {
        if (!agent.pathPending && agent.remainingDistance < 0.5f)
        {
            waitTimer += Time.deltaTime;
            if (waitTimer > waitTime)
            {
                SetRandomDestination();
                waitTimer = 0;
            }
        }
    }

    void SetRandomDestination()
    {
        Vector3 randomDir = Random.insideUnitSphere * patrolRadius;
        randomDir += startPos;
        NavMeshHit hit;
        if (NavMesh.SamplePosition(randomDir, out hit, patrolRadius, -1))
        {
            agent.SetDestination(hit.position);
        }
    }
}

Génère destinations random dans rayon, avec pause et priorités avoidance uniques (0-99). SamplePosition assure validité. Piège : Sans avoidancePriority random, collisions en troupeau ; scalez pour 50+ agents.

Query path avancé pour validation

Assets/Scripts/PathValidator.cs
using UnityEngine;
using UnityEngine.AI;

public class PathValidator : MonoBehaviour
{
    [SerializeField] private Transform target;
    private NavMeshAgent agent;
    private NavMeshPath path;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        path = new NavMeshPath();
    }

    void Update()
    {
        if (target != null)
        {
            NavMesh.CalculatePath(transform.position, target.position, NavMesh.AllAreas, path);
            if (path.status == NavMeshPathStatus.PathComplete)
            {
                Debug.Log($"Chemin valide, longueur: {path.CalculateCornerLength()}");
                agent.SetPath(path);
            }
            else
            {
                Debug.LogWarning("Chemin impossible !");
            }
        }
    }

    void OnDrawGizmos()
    {
        if (path != null)
        {
            Gizmos.color = Color.green;
            NavMeshVisualization.DrawPathGizmos(path);
        }
    }
}

Calcule et valide path avant SetDestination, log status/length. Gizmos visualise (ajoutez using UnityEngine.AI.NavMeshVisualization si custom). Piège : Ignore CalculatePath = paths foireux ; utilisez pour portes fermées.

Étape 5 : NavMesh runtime pour mondes procéduraux

NavMesh Surface > Build > Advanced > Use Geometry > Render Meshes.

Pour proc-gen : Appelez surface.BuildNavMesh() après spawn. Limite : Async pour perf.

Baking NavMesh runtime async

Assets/Scripts/RuntimeNavMeshBuilder.cs
using UnityEngine;
using UnityEngine.AI;

public class RuntimeNavMeshBuilder : MonoBehaviour
{
    [SerializeField] private NavMeshSurface navMeshSurface;

    [ContextMenu("Build NavMesh")]
    public async void BuildNavMeshAsync()
    {
        // Simule spawn procédural
        GameObject procGround = GameObject.CreatePrimitive(PrimitiveType.Plane);
        procGround.transform.position = new Vector3(10, 0, 10);
        procGround.AddComponent<NavMeshModifier>().OverrideArea = 0;

        await System.Threading.Tasks.Task.Run(() =>
        {
            navMeshSurface.BuildNavMesh();
        });

        Debug.Log("NavMesh rebaké runtime !");
    }
}

Construit NavMesh async après spawn procédural (Plane + Modifier). Task.Run offload CPU. Piège : Sync build freeze le jeu ; toujours async pour >1000 polys.

Bonnes pratiques

  • Voxel Size < 0.3 pour précision, mais testez FPS (bake time x10).
  • Priorités avoidance : Random 0-99 par agent, boss à 0 (priorité haute).
  • Areas & Costs : Multi-layers (eau cost 3.0) pour IA tactique.
  • Cache paths avec NavMesh.CalculatePath en coroutine.
  • Profiler > AI : Visez <1ms/frame pour 50 agents.

Erreurs courantes à éviter

  • Pas de Navigation Static : NavMesh vide, agents statiques.
  • Agent radius trop grand : Coincé dans portes étroites ; match geometry.
  • Bake sans SamplePosition : Destinations invalides, telerport.
  • Oubli carve sur obstacles mobiles : Agents traversent caisses.
  • Sync runtime bake : Lag spike ; forcez async.

Pour aller plus loin

Comment implémenter NavMesh IA Unity 2026 (Tutoriel) | Learni