Recherche de chemin est le processus de déplacement d'un personnage le long d'un chemin logique pour atteindre une destination, en évitant les obstacles et (facultativement) des matériaux dangereux ou des régions définies.
Visualisation de la navigation
Pour aider à la recherche de chemin et au débogage, Studio peut rendre un maillage de navigation et modifier les étiquettes.Pour les activer, activez maillage de navigation et modifieurs de chemin à partir du widget options de visualisation dans le coin supérieur droit du fenêtre de jeu3D.

Avec maille de navigation activée, les zones colorées montrent où un personnage pourrait marcher ou nager, tandis que les zones non colorées sont bloquées.Les petites flèches indiquent les zones que le personnage tentera d'atteindre en sautant, en supposant que vous avez défini à lorsque vous créez le chemin .

Avec modifieurs de recherche de chemin activés, les étiquettes de texte indiquent des matériaux et des régions spécifiques qui sont pris en compte lors de l'utilisation de modifieurs de recherche de chemin.

Limites connues
Les fonctionnalités de recherche de chemin ont des limitations spécifiques pour garantir un traitement efficace et des performances optimales.
Limite de placement vertical
Les calculs de recherche de chemin ne prennent en compte que les parties situées dans certaines limites verticales :
- Limite inférieure — Les parties avec une coordonnée inférieure Y à -65,536 sont ignorées.
- Limite supérieure — Les parties avec une coordonnée supérieure Y atteignant 65 536 studs sont ignorées.
- Espacement vertical — La distance verticale du point inférieur de la partie la plus basse Y à la coordonnée du sommet de la partie la plus élevée Y ne doit pas dépasser 65 536 studs ; sinon, le système de recherche de chemin ignorera ces parties pendant la recherche de chemin.
Limitation de la distance de recherche
La distance de ligne de vue directe pour la recherche de chemin depuis le point de départ jusqu'au point d'arrivée ne doit pas dépasser 3 000 studs.Dépasser cette distance entraînera un statut NoPath >.
Créer des chemins
La recherche de chemin est initiée via PathfindingService et sa fonction CreatePath().
Lecteur localScript
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath()
CreatePath() accepte une table facultative de paramètres qui précise comment le personnage (agent) se déplace le long du chemin.
Clé | Avertissement | Type | Par défaut |
---|---|---|---|
AgentRadius | Rayon de l'agent, en studs. Utile pour déterminer la séparation minimale des obstacles. | entier | 2 |
AgentHeight | Hauteur de l'agent, en studs. L'espace vide plus petit que cette valeur, comme l'espace sous les escaliers, sera marqué comme non traversable. | entier | 5 |
AgentCanJump | Détermine si le saut pendant la recherche de chemin est autorisé. | booléen | true |
AgentCanClimb | Détermine si l'escalade TrussParts pendant la recherche de chemin est autorisée. | booléen | false |
WaypointSpacing | Espacement entre les points de chemin intermédiaires dans le chemin. Si vous le définissez à math.huge, il n'y aura pas de points de chemin intermédiaires. | numéro | 4 |
Costs | Table de matériaux ou définie PathfindingModifiers et leur coût pour la traversée.Utile pour faire en sorte que l'agent préfère certains matériaux/régions à d'autres.Voir modifieurs pour les détails. | tableau | nil |
Lecteur localScript
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath({AgentRadius = 3,AgentHeight = 6,AgentCanJump = false,Costs = {Water = 20}})
Notez que l'agent peut escalader pendant la recherche de chemin en supposant que vous avez défini à lorsque vous créez le chemin et que rien ne bloque l'agent du chemin d'escalade.Un chemin escaladable a l'étiquette Montée et le coût pour un chemin escaladable est 1 par défaut.

LocalScript - Routede montée en truss
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath({AgentCanClimb = true,Costs = {Climb = 2 -- Coût du chemin d'escalade ; la valeur par défaut est 1}})
Avancer le long des chemins
Cette section utilise le script de recherche de chemin suivant pour le personnage du joueur. Pour tester en lisant :
- Copiez le code dans un LocalScript à l'intérieur de StarterCharacterScripts .
- Définissez la variable TEST_DESTINATION à une destination Vector3 dans votre monde 3D que le personnage joueur peut atteindre.
- Suivez les sections suivantes pour en savoir plus sur la計算路径 et le mouvement des caractères.
LocalScript - Recherche de caractères
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- Calculer le chemin
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenir les points de cheminement
waypoints = path:GetWaypoints()
-- Détecter si le chemin devient bloqué
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Vérifiez si l'obstacle est plus bas sur le chemin
if blockedWaypointIndex >= nextWaypointIndex then
-- Arrêter la détection du blocage du chemin jusqu'à ce que le chemin soit récalculé
blockedConnection:Disconnect()
-- Fonction d'appel pour récalculer le nouveau chemin
followPath(destination)
end
end)
-- Détecter lorsque le déplacement vers le prochain point de passage est terminé
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Augmenter l'index des points de passage et se déplacer au prochain point de passage
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Déplacez-vous initialement au deuxième point de passage (le premier point de passage est le commencerdu chemin ; sautez-le)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)
Calculer le chemin
Après avoir créé un chemin valide avec CreatePath() , il doit être calculé en appelant Path:ComputeAsync() avec un Vector3 pour le point de départ et la destination.
LocalScript - Recherche de caractères
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- Calculer le chemin
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
end

Obtenir des points de chemin
Une fois le Path calculé, il contiendra une série de points de passage qui tracera le chemin du début à terminer.Ces points peuvent être réunis avec la fonction Path:GetWaypoints().
LocalScript - Recherche de caractères
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- Calculer le chemin
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenir les points de cheminement
waypoints = path:GetWaypoints()
end
end

Déplacement du chemin
Chaque point de passage se compose à la fois d'une position () et d'une action () ().Pour déplacer un personnage contenant un Humanoid , comme un personnage typique de Roblox, le moyen le plus facile est d'appeler Humanoid:MoveTo() de point de chemin à point de chemin, en utilisant l'événement MoveToFinished pour détecter quand le personnage atteint chaque point de chemin.
LocalScript - Recherche de caractères
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- Calculer le chemin
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenir les points de cheminement
waypoints = path:GetWaypoints()
-- Détecter si le chemin devient bloqué
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Vérifiez si l'obstacle est plus bas sur le chemin
if blockedWaypointIndex >= nextWaypointIndex then
-- Arrêter la détection du blocage du chemin jusqu'à ce que le chemin soit récalculé
blockedConnection:Disconnect()
-- Fonction d'appel pour récalculer le nouveau chemin
followPath(destination)
end
end)
-- Détecter lorsque le déplacement vers le prochain point de passage est terminé
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Augmenter l'index des points de passage et se déplacer au prochain point de passage
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Déplacez-vous initialement au deuxième point de passage (le premier point de passage est le commencerdu chemin ; sautez-le)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
Gérer les chemins bloqués
De nombreux mondes Roblox sont dynamiques ; des parties peuvent se déplacer ou tomber, et des étages peuvent s'effondrer.Cela peut bloquer un chemin calculé et empêcher le personnage d'atteindre sa destination.Pour gérer cela, vous pouvez connecter l'événement Path.Blocked et récomputer le chemin autour de tout ce qui l'a bloqué.
LocalScript - Recherche de caractères
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- Calculer le chemin
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenir les points de cheminement
waypoints = path:GetWaypoints()
-- Détecter si le chemin devient bloqué
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Vérifiez si l'obstacle est plus bas sur le chemin
if blockedWaypointIndex >= nextWaypointIndex then
-- Arrêter la détection du blocage du chemin jusqu'à ce que le chemin soit récalculé
blockedConnection:Disconnect()
-- Fonction d'appel pour récalculer le nouveau chemin
followPath(destination)
end
end)
end
end
Modifieurs de recherche de chemin
Par défaut, retourne le chemin le plus court entre le point de départ et la destination, à l'exception qu'il essaie d'éviter les sauts.Cela semble artificiel dans certaines situations — par instance, un chemin peut traverser l'eau plutôt qu'au-dessus d'un pont proche simplement parce que le chemin à travers l'eau est plus court géométriquement.

Pour optimiser encore plus la recherche de chemin, vous pouvez implémenter modifieurs de recherche de chemin pour calculer des chemins plus intelligents à travers différents matériaux , autour de régions définies ou à travers des obstacles .
Définir les coûts matériels
Lorsque vous travaillez avec Terrain et BasePart matériaux, vous pouvez inclure une table Costs dans CreatePath() pour rendre certains matériaux plus traversables que d'autres.Tous les matériaux ont un coût par défaut de 1 et tout matériau peut être défini comme non traversable en définissant sa valeur à math.huge .
Les clés dans la table Costs doivent être des noms de chaîne représentant des noms Enum.Material par exemple Water pour Enum.Material.Water.
LocalScript - Recherche de caractères
local PathfindingService = game:GetService("PathfindingService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")local Workspace = game:GetService("Workspace")local path = PathfindingService:CreatePath({Costs = {Water = 20,Mud = 5,Neon = math.huge}})
Travailler avec des régions
Dans certains cas, la préférence du matériau n'est pas suffisante.Par exemple, vous voudrez peut-être que les personnages évitent une région définie , indépendamment des matériaux au sol.Cela peut être réalisé en ajoutant un objet PathfindingModifier à une partie.
Créez une partie Anchored autour de la région dangereuse et définissez sa propriété CanCollide à faux .
Insérez une instance PathfindingModifier sur la partie, localisez sa propriété Label et attribuez un nom significatif comme DangerZone .
Incluez une table Costs dans CreatePath() contenant une clé correspondante et une valeur numérique associée.Un modifieur peut être défini comme non traversable en définissant sa valeur à math.huge .
LocalScript - Recherche de caractèreslocal PathfindingService = game:GetService("PathfindingService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")local Workspace = game:GetService("Workspace")local path = PathfindingService:CreatePath({Costs = {DangerZone = math.huge}})
Ignorer les obstacles
Dans certains cas, il est utile de trouver un chemin à travers des obstacles solides comme s'ils n'existaient pas.Cela vous permet de calculer un chemin à travers des blocs physiques spécifiques, versus l'échec de la simulation à l'avance.
Créez une partie Anchored autour de l'objet et définissez sa propriété CanCollide à faux .
Insérez une instance PathfindingModifier sur la partie et activez sa propriété PassThrough.
Maintenant, lorsqu'un chemin est calculé du NPC zombie au personnage du joueur, le chemin s'étend au-delà de la porte et vous pouvez inciter le zombie à le traverser.Même si le zombie est incapable d'ouvrir la porte, il réagit comme s'il «entendait» le personnage derrière la porte.
Liens de recherche de chemin
Parfois, il est nécessaire de trouver un chemin à travers un espace qui ne peut pas être normalement traversé, comme à travers un gouffre, et d'effectuer une action personnalisée pour atteindre le prochain point de passage.Cela peut être réalisé via l'objet PathfindingLink.
En utilisant l'exemple de l'île ci-dessus, vous pouvez faire en sorte que l'agent utilise un bateau au lieu de traverser tous les ponts.

Pour créer un PathfindingLink à l'aide de cet exemple :
Pour aider à la visualisation et au débogage, activez les liens de recherche de chemin à partir du widget Options de visualisation dans le coin supérieur droit de la fenêtre de jeu3D.
Créez deux Attachments, l'un sur le siège du bateau et l'un près du point d'atterrissage du bateau.
Créez un objet PathfindingLink dans l'espace de travail, puis attribuez ses propriétés Attachement0 et Attachement1 aux annexes de départ et de fin respectivement.
Attribuez un nom significatif comme UseBoat à sa propriété Label.Ce nom est utilisé comme un drapeau dans le script de recherche de chemin pour déclencher une action personnalisée lorsque l'agent atteint le point de lien de départ.
Incluez une table Costs dans CreatePath() contenant à la fois une clé Water et une clé personnalisée correspondant au nom de propriété Label.Attribuez la clé personnalisée une valeur inférieure à Water .
LocalScript - Recherche de caractèreslocal PathfindingService = game:GetService("PathfindingService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")local Workspace = game:GetService("Workspace")local path = PathfindingService:CreatePath({Costs = {Water = 20,UseBoat = 1}})Dans l'événement qui se déclenche lorsqu'un point de passage est atteint, ajoutez un contrôle personnalisé pour le nom du modifieur Label et prenez une action différente de Humanoid:MoveTo() — dans ce cas, appelez une fonction pour installer l'agent dans le bateau, déplacer le bateau sur l'eau et poursuivre le chemin de l'agent lors de l'arrivée sur l'île de destination.
LocalScript - Recherche de caractèreslocal PathfindingService = game:GetService("PathfindingService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")local Workspace = game:GetService("Workspace")local path = PathfindingService:CreatePath({Costs = {Water = 20,UseBoat = 1}})local player = Players.LocalPlayerlocal character = player.Characterlocal humanoid = character:WaitForChild("Humanoid")local TEST_DESTINATION = Vector3.new(228.9, 17.8, 292.5)local waypointslocal nextWaypointIndexlocal reachedConnectionlocal blockedConnectionlocal function followPath(destination)-- Calculer le cheminlocal success, errorMessage = pcall(function()path:ComputeAsync(character.PrimaryPart.Position, destination)end)if success and path.Status == Enum.PathStatus.Success then-- Obtenir les points de cheminementwaypoints = path:GetWaypoints()-- Détecter si le chemin devient bloquéblockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)-- Vérifiez si l'obstacle est plus bas sur le cheminif blockedWaypointIndex >= nextWaypointIndex then-- Arrêter la détection du blocage du chemin jusqu'à ce que le chemin soit récalculéblockedConnection:Disconnect()-- Fonction d'appel pour récalculer le nouveau cheminfollowPath(destination)endend)-- Détecter lorsque le déplacement vers le prochain point de passage est terminéif not reachedConnection thenreachedConnection = humanoid.MoveToFinished:Connect(function(reached)if reached and nextWaypointIndex < #waypoints then-- Augmenter l'index des points de passage et se déplacer au prochain point de passagenextWaypointIndex += 1-- Utilisez le bateau si la balise de point de passage est "UseBoat"; sinon, déplacez-vous au prochain point de passageif waypoints[nextWaypointIndex].Label == "UseBoat" thenuseBoat()elsehumanoid:MoveTo(waypoints[nextWaypointIndex].Position)endelsereachedConnection:Disconnect()blockedConnection:Disconnect()endend)end-- Déplacez-vous initialement au deuxième point de passage (le premier point de passage est le commencerdu chemin ; sautez-le)nextWaypointIndex = 2humanoid:MoveTo(waypoints[nextWaypointIndex].Position)elsewarn("Path not computed!", errorMessage)endendfunction useBoat()local boat = Workspace.BoatModelhumanoid.Seated:Connect(function()-- Commencer à déplacer le bateau si l'agent est assisif humanoid.Sit thentask.wait(1)boat.CylindricalConstraint.Velocity = 5end-- Détecter la position de contrainte par rapport à l'îlelocal boatPositionConnectionboatPositionConnection = RunService.PostSimulation:Connect(function()-- Arrêter le bateau lorsque à côté de l'îleif boat.CylindricalConstraint.CurrentPosition >= 94 thenboatPositionConnection:Disconnect()boat.CylindricalConstraint.Velocity = 0task.wait(1)-- Déloger l'agent et poursuivre la destinationhumanoid.Sit = falsehumanoid:MoveTo(waypoints[nextWaypointIndex].Position)endend)end)endfollowPath(TEST_DESTINATION)
Compatibilité streaming
Le streaming d'instance en expérience est une fonctionnalité puissante qui charge et décharge dynamiquement du contenu 3D lorsque le personnage d'un joueur se déplace dans le monde.En explorant l'espace 3D, de nouveaux sous-ensembles de la chaîne d'espace se rendent sur leur appareil et certains des sous-ensembles existants pourraient s'écouler.
Considérez les meilleures pratiques suivantes pour l'utilisation de PathfindingService dans les expériences activées en streaming :
Le streaming peut bloquer ou débloquer un chemin donné à mesure qu'un personnage se déplace le long de celui-ci.Par exemple, alors qu'un personnage traverse une forêt, un arbre pourrait apparaître quelque part devant eux et obstruer le chemin.Pour que la recherche de chemin fonctionne sans problème avec le streaming, il est fortement recommandé d'utiliser la technique de gestion des chemins bloqués et de récalculer le chemin lorsque nécessaire.
Une approche commune dans la recherche de chemin consiste à utiliser les coordonnées des objets existants pour la計算 , telle que définir une destination de chemin à la position d'un modèle Coffre au trésor existant dans le monde.Cette approche est entièrement compatible avec le côté serveur Scripts puisque le serveur a une vue complète du monde en tout temps, mais LocalScripts et ModuleScripts ceux qui s'exécutent sur le client peuvent échouer si ils tentent de calculer un chemin vers un objet qui n'est pas diffusé en entrée.
Pour résoudre ce problème, envisagez de définir la destination à la position d'un BasePart dans un modèlisationpersistant permanent.Les modèles persistants se chargent peu après que le joueur ait rejoint et ne sont jamais diffusés, donc un script côté client peut se connecter à l'événement PersistentLoaded et accéder en toute sécurité au modèle pour créer des points de chemin après que l'événement se déclenche.