Búsqueda de caminos de personajes

*Este contenido se traduce usando la IA (Beta) y puede contener errores. Para ver esta página en inglés, haz clic en aquí.

Pathfinding es el proceso de mover a un personaje a lo largo de un camino lógico para alcanzar un destino, evitando obstáculos y (opcionalmente) materiales peligrosos o regiones definidas.

Visualización de navegación

Para ayudar con la búsqueda de caminos y el diagnóstico, Studio puede renderizar una malla de navegación y modificador etiquetas. Para habilitarlas, alterna búsqueda de malla y modificador desde el widget 2>Opciones de visualización2> en la esquina superior derecha de la ventana de vista 3D.

A close up view of the 3D viewport with the Visualization Options button indicated in the upper-right corner.

Con Navigation mesh habilitado, las áreas de color se muestran donde un personaje puede caminar o nadar, mientras que las áreas no de color están bloqueadas. Las pequeñas flechas indican áreas que un personaje intentará al saltar, asumiendo que estableces AgentCanJump a true cuando estés creando el camino.

Navigation mesh showing in Studio

Con modificadores de búsqueda de caminos habilitados, las etiquetas de texto indican materiales y regiones específicas que se tienen en cuenta al usar modificadores de búsqueda de caminos .

Navigation labels showing on navigation mesh

Límites conocidos

Las características de Pathfinding especifican limitaciones para garantizar un procesamiento eficiente y un ejecuciónóptimo.

Límite de colocación vertical

La búsqueda de rutas solo considera partes dentro de ciertos límites verticales:

  • Límite inferior — Las partes con un mínimo Y coordenadas inferior a -65,536 studs se ignoran.
  • Superior — Las partes con un máximo de Y coordenadas que exceden los 65,536 pies son ignoradas.
  • Espacio vertical — La distancia vertical desde la parte inferior más baja Y coordenada de la parte superior Y debe no exceder 65,536 studs; de lo contrario, el sistema de encontramiento de caminos ignorará esas partes durante la computación de encontramiento de caminos.

Límite de Distancia de Búsqueda

La distancia de línea de visión directa para la búsqueda de rutas desde el principio hasta el punto de finalización no debe exceder 3,000 studs. Exceder esta distancia resultará en un estado de NoPath .

Creando rutas

La búsqueda de ruta se inicia a través de PathfindingService y su función CreatePath()

Script local

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath()

CreatePath() acepta una tabla de parámetros opcional que ajusta cómo se mueve el personaje (agente) a lo largo del camino.

ClaveDescripciónTipoPor defecto
AgentRadiusRaíz del agente, en studs. Útil para determinar la separación mínima de los obstáculos.entero2
AgentHeightAltura del agente, en studs. Espacio vacío más pequeño que este valor, como el espacio debajo de las escaleras, se marcará como no transitable.entero5
AgentCanJumpDetermina si se permite saltar durante el cálculo del camino.booleanotrue
AgentCanClimbDetermina si se permite escalar TrussParts durante la búsqueda de caminos.booleanofalse
WaypointSpacingEspaciamiento entre los puntos de intermedio en el camino. Si se establece en math.huge, no habrá puntos de intermedio.número4
CostsTabla de materiales o definidos PathfindingModifiers y su costo por transitar. Útil para hacer que el agente prefiera ciertos materiales/regiones sobre otros. Consulte modificadores para obtener detalles.mesanil
Script local

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath({
AgentRadius = 3,
AgentHeight = 6,
AgentCanJump = false,
Costs = {
Water = 20
}
})

Nota que el agente puede escalar TrussParts durante el recorrido en caso de que establezca AgentCanClimb a true cuando crea el recorrido y nada bloquea el camino del agente desde el recorrido escalable. Un camino escalable

Path going up a climbable TrussPart ladder
LocalScript - rutade escalada de truss

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath({
AgentCanClimb = true,
Costs = {
Climb = 2 -- Coste del camino de escalada; el valor predeterminado es 1
}
})

Moverse por el camino

Esta sección usa el siguiente script de pathfinding para el personaje del jugador. Para probar mientras lees:

  1. Copia el código en un LocalScript dentro de StarterCharacterScripts .
  2. Edita la línea 11 a un destino Vector3 que el personaje del jugador puede alcanzar.
  3. Proceda a través de las siguientes secciones para aprender sobre la computación de caminos y el movimiento de personajes.
LocalScript - Características de rastro

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
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)
-- Computa el camino
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtener los puntos de camino
waypoints = path:GetWaypoints()
-- Detecta si el camino se bloquea
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Compruebe si el obstáculo está más abajo en el camino
if blockedWaypointIndex >= nextWaypointIndex then
-- Deja de detectar bloqueo de camino hasta que se recompense el camino
blockedConnection:Disconnect()
-- Llamar función para re-计算 nuevo camino
followPath(destination)
end
end)
-- Detecta cuando el movimiento a la siguiente dirección esté completado
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumentar el índice de puntos de interés y moverse al siguiente punto de interés
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inicialmente se mueve al segundo punto de intersección (el primer punto de intersección es el iniciardel camino; saltarlo)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)

Cálculo del ruta

Después de que hayas creado un camino válido con CreatePath() , debe ser calculado al llamar a Path:ComputeAsync() con un 1> Datatype.Vector31> para ambos el punto de partida y el destino.

LocalScript - Características de rastro

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
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)
-- Computa el camino
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
end
Path start/end marked on series of islands and bridges

Obtener Waypoints

Una vez que se haya calculado el Path, contendrá una serie de puntos de intersección que rastrean el camino desde el principio hasta finalizar. Estos puntos se pueden recopilar con la función Path:GetWaypoints().

LocalScript - Características de rastro

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
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)
-- Computa el camino
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtener los puntos de camino
waypoints = path:GetWaypoints()
end
end
Waypoints indicated across computed path
Puntos de destino indicados en el camino calculado

Movimiento de Camino

Cada waypoint consiste en ambos un posición ( Vector3 ) y un acción ( 1> Class.Humanoid:MoveTo|PathWay

LocalScript - Características de rastro

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
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)
-- Computa el camino
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtener los puntos de camino
waypoints = path:GetWaypoints()
-- Detecta si el camino se bloquea
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Compruebe si el obstáculo está más abajo en el camino
if blockedWaypointIndex >= nextWaypointIndex then
-- Deja de detectar bloqueo de camino hasta que se recompense el camino
blockedConnection:Disconnect()
-- Llamar función para re-计算 nuevo camino
followPath(destination)
end
end)
-- Detecta cuando el movimiento a la siguiente dirección esté completado
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumentar el índice de puntos de interés y moverse al siguiente punto de interés
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inicialmente se mueve al segundo punto de intersección (el primer punto de intersección es el iniciardel camino; saltarlo)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end

Manipulando Caminos Bloqueados

Muchos mundos de Roblox son dinámicos; las partes pueden moverse o caer y los pisos pueden colapsar. Esto puede bloquear un camino calculado y evitar que el personaje alcance su destino. Para manejar esto, puede conectar el evento Path.Blocked y recompilar el camino alrededor de lo que bloqueó.

LocalScript - Características de rastro

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
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)
-- Computa el camino
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtener los puntos de camino
waypoints = path:GetWaypoints()
-- Detecta si el camino se bloquea
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Compruebe si el obstáculo está más abajo en el camino
if blockedWaypointIndex >= nextWaypointIndex then
-- Deja de detectar bloqueo de camino hasta que se recompense el camino
blockedConnection:Disconnect()
-- Llamar función para re-计算 nuevo camino
followPath(destination)
end
end)
end
end

Modificadores de búsqueda de caminos

Por defecto, Path:ComputeAsync() devuelve el camino más corto entre el punto de inicio y el destino, con la excepción de que intenta evitar los saltos. Esto se ve poco natural en algunas situaciones, por instancia, un camino puede ir a través del agua en lugar de sobre un puente cercano simplemente porque el camino a través del agua es geométricamente más corto.

Two paths indicated with the shorter path not necessarily more logical

Para optimizar aún más el encontrado de caminos, puede implementar modificadores de encontrado de caminos para calcular rutas más inteligentes en varios 材料 , alrededor de las regiones definidas regiones o a través de 1>obstáculos1>.

Estableciendo Costos de Material

Cuando trabajas con Terrain y BasePart materiales, puedes incluir una tabla de Costs dentro de 1> Class.PathfindingService:CreatePath()|CreatePath()1> para hacer que algunos materiales sean más traversables

Las llaves en la Costs tabla deben ser nombres de cuerda que representan nombres de Enum.Material nombres, por ejemplo, Water para 1> Enmarca.Material.Water1> .

LocalScript - Características de rastro

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local path = PathfindingService:CreatePath({
Costs = {
Water = 20,
Mud = 5,
Neon = math.huge
}
})

Trabajar con regiones

En algunos casos, preferencia de material no es suficiente. Por ejemplo, puede que quieras que los personajes eviten una región definida , independientemente de los materiales debajo de los pies. Esto se puede lograr agregando un objeto PathfindingModifier a una parte.

  1. Crea una parte de Anchored alrededor de la región peligrosa y establece su propiedad de CanCollide a falso .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Inserta una instancia de PathfindingModifier a la parte, localiza su propiedad Label y asigna un nombre significativo como DangerZone .

    PathfindingModifier instance with Label property set to DangerZone
  3. Incluya una tabla Costs dentro de CreatePath() que contenga una clave y un valor numérico correspondiente. Un modificador se puede definir como no trazable al establecer su valor a math.huge .

    LocalScript - Características de rastro

    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local path = PathfindingService:CreatePath({
    Costs = {
    DangerZone = math.huge
    }
    })

Ignorando obstáculos

En algunos casos, puede ser útil encontrar el camino a través de obstáculos sólidos como si no existieran. Esto te permite calcular un camino a través de bloqueadores físicos específicos, en lugar de que la computación fracase.

  1. Crea una parte de Anchored alrededor del objeto y establece su propiedad de CanCollide a falso .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Inserta una instancia de PathfindingModifier a la parte y habilita su propiedad PassThrough.

    PathfindingModifier instance with PassThrough property enabled

    Ahora, cuando se calcula un camino desde el NPC zombie al personaje del jugador, el camino se extiende más allá de la puerta y puedes solicitar al zombie que lo atraviese. Incluso si el zombie no puede abrir la puerta, reacciona como si "oiese" al personaje detrás de la puerta.

    Zombie NPC path passing through the previously blocking door

Enlaces de búsqueda de caminos

A veces es necesario encontrar un camino a través de un espacio que no se puede atravesar normalmente, como a través de un acantilado, y realizar una acción personalizada para alcanzar el próximo punto de enlace. Esto se puede lograr a través del objeto PathfindingLink.

Usando el ejemplo de la isla de arriba, puede hacer que el agente use un bote en lugar de caminar a través de todos los puentes.

PathfindingLink showing how an agent can use a boat instead of walking across all of the bridges

Para crear un PathfindingLink usando este ejemplo:

  1. Para ayudar con la visualización y el diagnóstico, alterna enlaces de enfoque de visión desde el widget Opciones de visualización en la esquina superior derecha de la ventana de vista 3D.

  2. Crea dos Attachments , uno en el asiento del barco y uno cerca del punto de aterrizaje del barco.

    Attachments created for pathfinding link's start and end
  3. Crea un objeto PathfindingLink en el espacio de trabajo, luego asigna sus propiedades de Accesorio0 y Accesorio1 a los accesorios de inicio y fin respectivamente.

    Attachment0/Attachment1 properties of a PathfindingLink PathfindingLink visualized in the 3D world
  4. Asigne un nombre significativo como UseBoat a su propiedad Label . Este nombre se utiliza como una bandera en el script de enrutamiento para activar una acción personalizada cuando el agente llega al punto de inicio de enlace.

    Label property specified for PathfindingLink
  5. Incluya una tabla de Costs dentro de CreatePath() que contenga tanto una llave de Water como una llave personalizada que coincida con el nombre de propiedad de la 1> Class.PathfindingLink.Label|Label1> propiedad. Asigna la llave personalizada un valor inferior a 4> Water4> .

    LocalScript - Características de rastro

    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local path = PathfindingService:CreatePath({
    Costs = {
    Water = 20,
    UseBoat = 1
    }
    })
  6. En el evento que se activa cuando se alcanza un enlace de dirección, agregue un cheque personalizado para el nombre del modificador Label y tome una acción diferente que Humanoid:MoveTo() — en este caso, llamar a una función para sentar al agente en el bote, mover el bote a través del agua y continuar el camino del agente al llegar a la isla de destino

    LocalScript - Características de rastro

    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local path = PathfindingService:CreatePath({
    Costs = {
    Water = 20,
    UseBoat = 1
    }
    })
    local player = Players.LocalPlayer
    local character = player.Character
    local humanoid = character:WaitForChild("Humanoid")
    local TEST_DESTINATION = Vector3.new(228.9, 17.8, 292.5)
    local waypoints
    local nextWaypointIndex
    local reachedConnection
    local blockedConnection
    local function followPath(destination)
    -- Computa el camino
    local success, errorMessage = pcall(function()
    path:ComputeAsync(character.PrimaryPart.Position, destination)
    end)
    if success and path.Status == Enum.PathStatus.Success then
    -- Obtener los puntos de camino
    waypoints = path:GetWaypoints()
    -- Detecta si el camino se bloquea
    blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
    -- Compruebe si el obstáculo está más abajo en el camino
    if blockedWaypointIndex >= nextWaypointIndex then
    -- Deja de detectar bloqueo de camino hasta que se recompense el camino
    blockedConnection:Disconnect()
    -- Llamar función para re-计算 nuevo camino
    followPath(destination)
    end
    end)
    -- Detecta cuando el movimiento a la siguiente dirección esté completado
    if not reachedConnection then
    reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
    if reached and nextWaypointIndex < #waypoints then
    -- Aumentar el índice de puntos de interés y moverse al siguiente punto de interés
    nextWaypointIndex += 1
    -- Usa el bote si el etiqueta de la salida es "UseBoat"; de lo contrario, mueve al siguiente punto de salida
    if waypoints[nextWaypointIndex].Label == "UseBoat" then
    useBoat()
    else
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    else
    reachedConnection:Disconnect()
    blockedConnection:Disconnect()
    end
    end)
    end
    -- Inicialmente se mueve al segundo punto de intersección (el primer punto de intersección es el iniciardel camino; saltarlo)
    nextWaypointIndex = 2
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    else
    warn("Path not computed!", errorMessage)
    end
    end
    function useBoat()
    local boat = workspace.BoatModel
    humanoid.Seated:Connect(function()
    -- Iniciar el movimiento del bote si el agente está sentado
    if humanoid.Sit then
    task.wait(1)
    boat.CylindricalConstraint.Velocity = 5
    end
    -- Detectar la posición de restricción en relación con la isla
    local boatPositionConnection
    boatPositionConnection = RunService.PostSimulation:Connect(function()
    -- Detener el barco al lado de la isla
    if boat.CylindricalConstraint.CurrentPosition >= 94 then
    boatPositionConnection:Disconnect()
    boat.CylindricalConstraint.Velocity = 0
    task.wait(1)
    -- Deseleccionar agente y continuar con la destrucción
    humanoid.Sit = false
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    end)
    end)
    end
    followPath(TEST_DESTINATION)

Compatibilidad con streaming

En-experience streaming de instancia es una poderosa característica que carga y descarga dinámicamente el contenido 3D como un jugadorde su personaje mientras se mueve por el mundo. Mientras exploran el espacio 3D, nuevos subconjuntos del espacio stream a su dispositivo y algunos de los subconjuntos existentes pueden stream out.

Tenga en cuenta las siguientes mejores prácticas para usar PathfindingService en experiencias habilitadas para streaming:

  • El streaming puede bloquear o desbloquear un camino específico mientras un personaje se mueve por él. Por ejemplo, mientras un personaje corre a través de un bosque, un árbol puede aparecer en algún lugar y obstruir el camino. Para que funcione la búsqueda de caminos sin problemas con el streaming, se recomienda altamente que uses la técnica Manejar bloqueados caminos y re-计算 el camino cuando sea necesario.

  • Un enfoque común en la búsqueda de caminos es usar las coordenadas de los objetos existentes para la 计算 , como establecer un destino de camino a la posición de un modelo de Cofre de Tesoro existente

    Para abordar este problema, considere establecer el destino en la posición de un BasePart dentro de un aplicación de modeladopersistente dentro de un modelo PersistentLoaded dentro de un modelo 2>persistente2> dentro de un modelo 5>persistente5> dentro de un modelo 8>persistente8> dentro de un modelo BasePart1> dentro de