GM Market — Premium GMod & FiveM Scripts
Roblox Guide 🇫🇷 Français

Guide complet : PathfindingService pour créer un NPC qui suit le joueur sur Roblox

>*Muzan Moderator
@>*Muzan · Moderator ·
7 views 0 replies

TL;DR

Tu veux un NPC capable de naviguer dans ton map, contourner les obstacles et suivre un joueur en temps réel ? Ce guide couvre tout : PathfindingService, ComputeAsync, les waypoints et la gestion de l'événement Blocked. Niveau intermédiaire, Script serveur uniquement.


Pourquoi PathfindingService ?

Déplacer un NPC avec un simple Humanoid:MoveTo() fonctionne en ligne droite, mais dès qu'un mur s'interpose, le personnage reste bloqué. PathfindingService permet aux NPCs de suivre des chemins, d'interagir avec les joueurs et d'exécuter toutes sortes de tâches grâce au scripting.

Le flux de travail est toujours le même :

  1. Créer un Path via CreatePath()
  2. Calculer le chemin avec ComputeAsync()
  3. Récupérer les waypoints avec GetWaypoints()
  4. Faire avancer le NPC de waypoint en waypoint
  5. Gérer les blocages dynamiques avec path.Blocked

Étape 1 — Préparer la scène

  • Place un modèle de personnage (avec Humanoid + HumanoidRootPart) dans le Workspace, nommé NPC.
  • Mets un Script serveur directement dans le modèle. Cette approche est pleinement compatible avec les Scripts serveur, car le serveur a une vue complète du monde à tout moment ; les LocalScript peuvent échouer si l'objet cible n'est pas encore streamé côté client.
  • Active la Navigation Mesh pour visualiser les zones traversables : dans l'onglet Studio, section Visualization, active Show Navigation Mesh.

Étape 2 — Paramètres de CreatePath

PathfindingService:CreatePath() accepte une table optionnelle de paramètres qui affinent la façon dont le personnage (agent) se déplace sur le chemin.

ParamètreDéfautDescription
AgentRadius2Rayon en studs — espace minimal par rapport aux obstacles
AgentHeight5Hauteur de l'agent : les espaces vides plus petits que cette valeur seront marqués non traversables.
AgentCanJumptrueAutorise le saut
AgentCanClimbfalseAutorise la montée sur les TrussPart.
WaypointSpacing4Espacement entre waypoints intermédiaires
CostsnilTable de matériaux/PathfindingModifier et leur coût — utile pour que l'agent préfère certaines zones.

Conseil AgentRadius : le syndrome du "bloqué dans les coins" survient quand l'AgentRadius est trop petit — le pathfinder croit que le NPC peut passer, mais ses parties physiques sont plus larges que le chemin calculé. Ajouter un petit buffer (ex. 2,5 ou 3) évite que le NPC frôle les murs.


Étape 3 — ComputeAsync et waypoints

Une fois un chemin valide créé, il doit être calculé en appelant Path:ComputeAsync() avec un Vector3 pour le point de départ et la destination. Le chemin contient ensuite une série de waypoints du début à la fin, récupérables avec Path:GetWaypoints() — le tableau est ordonné du premier au dernier waypoint.

local PathfindingService = game:GetService("PathfindingService")

local NPC      = script.Parent
local humanoid = NPC:WaitForChild("Humanoid")
local rootPart = NPC:WaitForChild("HumanoidRootPart")

local path = PathfindingService:CreatePath({
    AgentRadius  = 3,
    AgentHeight  = 6,
    AgentCanJump = true,
})

local function allerVers(destination)
    path:ComputeAsync(rootPart.Position, destination)

    if path.Status ~= Enum.PathStatus.Success then
        warn("Chemin introuvable :", path.Status)
        return
    end

    for _, waypoint in ipairs(path:GetWaypoints()) do
        if waypoint.Action == Enum.PathWaypointAction.Jump then
            humanoid.Jump = true
        end
        humanoid:MoveTo(waypoint.Position)
        humanoid.MoveToFinished:Wait()
    end
end

Préfère MoveToFinished:Wait() à une boucle while manuelle : l'événement se déclenche automatiquement quand le NPC atteint la cible, ou après un timeout de 8 secondes si le NPC est bloqué.


Étape 4 — Gestion des blocages dynamiques

Le chemin peut devenir invalide en cours de route (porte qui se ferme, objet posé par un joueur…). Path.Blocked:Connect() permet de réagir automatiquement : dès qu'un obstacle bloque le chemin calculé, le NPC peut recalculer un nouveau trajet, ce qui le rend bien plus réactif.

local estBloque = false

path.Blocked:Connect(function()
    estBloque = true
end)

Connecte cet événement avant d'appeler ComputeAsync, et sur le même objet path réutilisé tout au long de la vie du NPC — si tu recrées path à chaque itération, tu perds les connexions précédentes.


Script complet — NPC qui suit le joueur le plus proche

local PathfindingService = game:GetService("PathfindingService")
local Players            = game:GetService("Players")

local NPC      = script.Parent
local humanoid = NPC:WaitForChild("Humanoid")
local rootPart = NPC:WaitForChild("HumanoidRootPart")

local RAYON_DETECTION = 100
local DELAI_RECALCUL  = 0.5

local path      = PathfindingService:CreatePath({
    AgentRadius  = 3,
    AgentHeight  = 6,
    AgentCanJump = true,
})
local estBloque = false

path.Blocked:Connect(function()
    estBloque = true
end)

local function joueurLePlusProche()
    local meilleur, distMin = nil, RAYON_DETECTION
    for _, joueur in ipairs(Players:GetPlayers()) do
        local perso = joueur.Character
        if perso and perso:FindFirstChild("HumanoidRootPart") then
            local dist = (rootPart.Position - perso.HumanoidRootPart.Position).Magnitude
            if dist < distMin then
                meilleur, distMin = perso, dist
            end
        end
    end
    return meilleur
end

while task.wait(DELAI_RECALCUL) do
    local cible = joueurLePlusProche()
    if not cible then continue end

    estBloque = false
    path:ComputeAsync(rootPart.Position, cible.HumanoidRootPart.Position)

    if path.Status ~= Enum.PathStatus.Success then continue end

    for _, waypoint in ipairs(path:GetWaypoints()) do
        if estBloque then break end

        if waypoint.Action == Enum.PathWaypointAction.Jump then
            humanoid.Jump = true
        end

        humanoid:MoveTo(waypoint.Position)
        if not humanoid.MoveToFinished:Wait() then
            estBloque = true
            break
        end
    end
end

Pièges courants

NPC bloqué sur les coins / petits murs

Augmente AgentRadius de 0,5 à 1 stud par rapport à la moitié de la largeur réelle du modèle.

NPC parfait en mode Run mais bloqué en mode Play

Ce symptôme classique est souvent lié au personnage du joueur lui-même qui obstrue le chemin calculé. Réduire DELAI_RECALCUL et activer path.Blocked règle généralement le problème.

ComputeAsync appelé trop fréquemment = lag

Appeler ComputeAsync en permanence pour chaque NPC peut tuer les performances — mieux vaut ne recalculer que toutes les quelques secondes, ou quand le NPC s'écarte nettement de son chemin.

path.Blocked qui ne se déclenche jamais

Vérifie que la connexion est faite avant ComputeAsync et que tu réutilises le même objet path (ne le recrée pas dans la boucle).


Aller plus loin

  • PathfindingModifier : ces modificateurs permettent de définir des zones où le comportement de pathfinding change — pratique pour des zones restreintes ou à règles de déplacement spécifiques.
  • PathfindingLink : pour traverser un espace normalement infranchissable (un ravin, par exemple) et exécuter une action personnalisée, utilise l'objet PathfindingLink.
  • Debug des waypoints : afficher le chemin avec des parts placées à chaque waypoint pendant le développement aide à comprendre pourquoi un NPC se bloque ou prend un itinéraire inattendu.

Tu trouveras aussi des systèmes d'IA et de NPC prêts à l'emploi sur le marketplace GM Market si tu cherches une base solide à personnaliser.


FAQ

Q : Puis-je utiliser ce système dans un LocalScript ? Techniquement oui pour un NPC client, mais c'est déconseillé : les LocalScript peuvent échouer si l'objet cible n'est pas encore streamé côté client. Préfère toujours le serveur.

Q : Comment faire sauter le NPC ? Vérifie waypoint.Action == Enum.PathWaypointAction.Jump avant chaque MoveTo, comme dans le script complet ci-dessus.

Q : Quelle valeur pour WaypointSpacing ? La valeur par défaut de 4 studs convient pour la majorité des maps. Réduis-la pour des couloirs très étroits ; augmente-la pour des espaces ouverts afin de limiter le nombre de waypoints et améliorer les performances.

Q : Mon NPC ne saute pas les obstacles alors que AgentCanJump = true. Assure-toi que ta map est correctement détectée par la Navigation Mesh. Les parties avec CanCollide = false ne sont généralement pas considérées comme obstacles — vérifie les propriétés de collision de tes parts.

0

0 Replies

No replies yet — be the first to respond.