Encontro de caminho de personagem

*Este conteúdo é traduzido por IA (Beta) e pode conter erros. Para ver a página em inglês, clique aqui.

Encontrar Caminho é o processo de mover um personagem ao longo de um caminho lógico para chegar a um destino, evitando obstáculos e (opcionalmente) materiais perigosos ou regiões definidas.

Visualização de navegação

Para ajudar com o planejamento de caminho e depuração, o Studio pode renderizar uma malha de navegação e rótulos modificadores.Para ativá-los, ative Modelo de navegação e Modificadores de busca de caminho a partir do widget Opções de visualização no canto superior direito do janela3D.

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

Com malha de navegação ativada, áreas coloridas mostram onde um personagem pode caminhar ou nadar, enquanto áreas não coloridas são bloqueadas.As setas pequenas indicam áreas que um personagem tentará alcançar pulando, assumindo que você defina AgentCanJump para true quando criar o caminho .

Navigation mesh showing in Studio

Com modificadores de busca de caminho ativados, rótulos de texto indicam materiais e regiões específicos que são levados em consideração ao usar modificadores de busca de caminho.

Navigation labels showing on navigation mesh

Limitações conhecidas

Os recursos de localização de caminho têm limitações específicas para garantir processamento eficiente e performanceotimizado.

Limite de colocação vertical

As calificações de busca de caminho consideram apenas partes dentro de certos limites verticais:

  • Limite Inferior — Peças com uma coordenada inferior de Y menos de -65,536 metros são ignoradas.
  • Limite superior — Peças com uma coordenada superior Y excedendo 65.536 studs são ignoradas.
  • Espaço vertical — A distância vertical do lado inferior da parte mais baixa Y para o lado superior da parte mais alta Y deve não exceder 65,536 studs; caso contrário, o sistema de busca de caminho ignorará essas partes durante a busca de caminho.

Limitação de distância de busca

A distância direta de visão para o caminho desde o ponto de partida até o ponto de chegada não deve exceder 3.000 metros.Exceder essa distância resultará em um status NoPath de.

Criar caminhos

O encontramento de caminho é iniciado através de PathfindingService e sua função CreatePath().

LocalScript

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

CreatePath() aceita uma tabela opcional de parâmetros que refina como o personagem (agente) se move ao longo do caminho.

ChaveDescriçãoTipoPadrão
AgentRadiusRaio do agente, em studs. Útil para determinar a separação mínima de obstáculos.integral2
AgentHeightAltura do agente, em studs. Espaço vazio menor que esse valor, como o espaço sob as escadas, será marcado como não trilável.integral5
AgentCanJumpDetermina se o pulo durante a busca de caminho é permitido.booleanotrue
AgentCanClimbDetermina se é permitido escalar TrussParts durante a busca de caminho.booleanofalse
WaypointSpacingEspaçamento entre pontos de caminho intermediários no caminho. Se definido para math.huge, não haverá pontos de caminho intermediários.número4
CostsTabela de materiais ou definidos PathfindingModifiers e seu custo para trânsito.Útil para fazer com que o agente prefira determinados materiais/regiões sobre outros.Veja modificadores para detalhes.tabelanil
LocalScript

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

Observe que o agente pode escalar TrussParts durante o caminho de busca assumindo que você defina AgentCanClimb para true quando criar o caminho e nada bloqueia o agente do caminho de escalada da treliça.Um caminho escalável tem a etiqueta Subida e o custo para uma subida escalável é 1 por padrão.

Path going up a climbable TrussPart ladder
LocalScript - Caminho de Escalada de Treliça

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath({
AgentCanClimb = true,
Costs = {
Climb = 2 -- Custo do caminho de escalada; o padrão é 1
}
})

Mova-se ao longo de caminhos

Esta seção usa o seguinte script de busca de caminho para o personagem do jogador. Para testar enquanto lê:

  1. Copie o código em um LocalScript dentro de StarterCharacterScripts.
  2. Defina a variável TEST_DESTINATION para um destino Vector3 no seu mundo 3D que o personagem do jogador possa alcançar.
  3. Prossiga pelas seções a seguir para aprender sobre a computação de caminho e o movimento de personagens.
LocalScript - Encontro de Caminho de Personagem

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)
-- Calcular o caminho
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenha os pontos de caminho
waypoints = path:GetWaypoints()
-- Detectar se o caminho se torna bloqueado
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Verifique se o obstáculo está mais abaixo do caminho
if blockedWaypointIndex >= nextWaypointIndex then
-- Pare de detectar bloqueio de caminho até que o caminho seja recomputado
blockedConnection:Disconnect()
-- Chame a função para recalcular o novo caminho
followPath(destination)
end
end)
-- Detectar quando o movimento para o próximo waypoint estiver completo
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumentar o índice de pontos de caminho e mover para o próximo pontos de caminho
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inicialmente mova-se para o segundo waypoint (o primeiro waypoint é o iniciardo caminho; pule-o)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)

Calcular o caminho

Depois de ter criado um caminho válido com CreatePath() , deve ser calculado ao chamar Path:ComputeAsync() com um Vector3 para o ponto de partida e destino.

LocalScript - Encontro de Caminho de Personagem

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)
-- Calcular o caminho
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
end
Path start/end marked on series of islands and bridges

Obter pontos de caminho

Uma vez que o Path é calculado, ele conterá uma série de pontos de caminho que rastreiam o caminho de início a terminar/parar/sair.Esses pontos podem ser reunidos com a função Path:GetWaypoints().

LocalScript - Encontro de Caminho de Personagem

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)
-- Calcular o caminho
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenha os pontos de caminho
waypoints = path:GetWaypoints()
end
end
Waypoints indicated across computed path
Pontos de caminho indicados ao longo do caminho computado

Movimento de caminho

Cada ponto de caminho consiste em ambas uma posição () e uma ação () ).Para mover um personagem que contém um Humanoid , como um personagem típico do Roblox, a maneira mais fácil é chamar Humanoid:MoveTo() de um ponto de caminho para o outro, usando o evento MoveToFinished para detectar quando o personagem chega a cada ponto de caminho.

LocalScript - Encontro de Caminho de Personagem

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)
-- Calcular o caminho
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenha os pontos de caminho
waypoints = path:GetWaypoints()
-- Detectar se o caminho se torna bloqueado
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Verifique se o obstáculo está mais abaixo do caminho
if blockedWaypointIndex >= nextWaypointIndex then
-- Pare de detectar bloqueio de caminho até que o caminho seja recomputado
blockedConnection:Disconnect()
-- Chame a função para recalcular o novo caminho
followPath(destination)
end
end)
-- Detectar quando o movimento para o próximo waypoint estiver completo
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumentar o índice de pontos de caminho e mover para o próximo pontos de caminho
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inicialmente mova-se para o segundo waypoint (o primeiro waypoint é o iniciardo caminho; pule-o)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end

Lidar com caminhos bloqueados

Muitos mundos do Roblox são dinâmicos; peças podem se mover ou cair e pisos podem colapsar.Isso pode bloquear um caminho computado e impedir que o personagem chegue ao destino.Para lidar com isso, você pode conectar o evento Path.Blocked e recomputar o caminho em torno de qualquer coisa que o bloqueou.

LocalScript - Encontro de Caminho de Personagem

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)
-- Calcular o caminho
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Obtenha os pontos de caminho
waypoints = path:GetWaypoints()
-- Detectar se o caminho se torna bloqueado
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Verifique se o obstáculo está mais abaixo do caminho
if blockedWaypointIndex >= nextWaypointIndex then
-- Pare de detectar bloqueio de caminho até que o caminho seja recomputado
blockedConnection:Disconnect()
-- Chame a função para recalcular o novo caminho
followPath(destination)
end
end)
end
end

Modificadores de busca de caminho

Por padrão, Path:ComputeAsync() retorna o caminho mais curto entre o ponto de partida e o destino, com a exceção de que tenta evitar saltos.Isso parece pouco natural em algumas situações - por instância, um caminho pode passar por água em vez de sobre uma ponte próxima simplesmente porque o caminho através de água é geometricamente mais curto.

Two paths indicated with the shorter path not necessarily more logical

Para otimizar ainda mais a busca de caminho, você pode implementar modificadores de busca de caminho para calcular caminhos mais inteligentes através de vários materiais , ao redor de regiões definidas ou através de obstáculos .

Definir custos de materiais

Ao trabalhar com Terrain e BasePart materiais, você pode incluir uma tabela Costs dentro de CreatePath() para tornar alguns materiais mais atravessáveis do que outros.Todos os materiais têm um custo padrão de 1 e qualquer material pode ser definido como não atravessável definindo seu valor para math.huge .

Chaves na tabela Costs devem ser nomes de corda que representam nomes Enum.Material , por exemplo Water para Enum.Material.Water .

LocalScript - Encontro de Caminho de Personagem

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
}
})

Trabalhar com regiões

Em alguns casos, preferência de material não é suficiente.Por exemplo, você pode querer que os personagens evitem uma região definida , independentemente dos materiais embaixo.Isso pode ser alcançado adicionando um objeto PathfindingModifier a uma peça.

  1. Crie uma peça Anchored ao redor da região perigosa e defina sua propriedade CanCollide para falso .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Insira uma instância PathfindingModifier em parte, localize sua propriedade Label e atribua um nome significativo como Zona de Perigo .

    PathfindingModifier instance with Label property set to DangerZone
  3. Inclua uma tabela Costs dentro de CreatePath() que contenha uma chave correspondente e um valor numérico associado.Um modificador pode ser definido como não atravessável ao definir seu valor para math.huge .

    LocalScript - Encontro de Caminho de Personagem

    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 = {
    DangerZone = math.huge
    }
    })

Ignorar obstáculos

Em alguns casos, é útil encontrar um caminho através de obstáculos sólidos como se eles não existissem.Isso permite que você calcule um caminho através de bloqueadores físicos específicos, versus a computação falhar completamente.

  1. Crie uma peça Anchored ao redor do objeto e defina sua propriedade CanCollide para falso .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Insira uma instância PathfindingModifier em parte e habilite sua propriedade PassThrough.

    PathfindingModifier instance with PassThrough property enabled

    Agora, quando um caminho é computado do NPC zumbi para o personagem do jogador, o caminho se estende além da porta e você pode solicitar que o zumbi o atravesse.Mesmo que o zumbi não consiga abrir a porta, ele reage como se "ouvisse" o personagem atrás da porta.

    Zombie NPC path passing through the previously blocking door

Às vezes, é necessário encontrar um caminho através de um espaço que não pode ser normalmente percorrido, como através de um abismo, e executar uma ação personalizada para chegar ao próximo destino.Isso pode ser alcançado através do ObjetoPathfindingLink.

Usando o exemplo da ilha acima, você pode fazer com que o agente use um barco em vez de caminhar por todas as pontes.

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

Para criar um PathfindingLink usando este exemplo:

  1. Para ajudar com a visualização e depuração, ative links de busca de caminho a partir do widget Opções de Visualização no canto superior direito do janela3D.

  2. Crie dois Attachments, um no assento do barco e um perto do ponto de desembarco do barco.

    Attachments created for pathfinding link's start and end
  3. Crie um objeto PathfindingLink na área de trabalho, então atribua suas propriedades Attachment0 e Attachment1 às respectivas anexos iniciais e finais, respectivamente.

    Attachment0/Attachment1 properties of a PathfindingLink PathfindingLink visualized in the 3D world
  4. Atribua um nome significativo como UseBoat à sua propriedade Label.Este nome é usado como uma bandeira no script de busca de caminho para ativar uma ação personalizada quando o agente chegar ao ponto de ligação inicial.

    Label property specified for PathfindingLink
  5. Inclua uma tabela Costs dentro de CreatePath() que contenha tanto uma chave Water quanto uma chave personalizada que corresponda ao nome da propriedade Label.Atribua a chave personalizada um valor inferior a Water .

    LocalScript - Encontro de Caminho de Personagem

    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,
    UseBoat = 1
    }
    })
  6. No evento que dispara quando um caminho for alcançado, adicione uma verificação personalizada para o nome do modificador Label e tome uma ação diferente da Humanoid:MoveTo() - neste caso, chamando uma função para sentar o agente no barco, mover o barco através da água e continuar o caminho do agente após chegar à ilha de destino.

    LocalScript - Encontro de Caminho de Personagem

    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,
    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)
    -- Calcular o caminho
    local success, errorMessage = pcall(function()
    path:ComputeAsync(character.PrimaryPart.Position, destination)
    end)
    if success and path.Status == Enum.PathStatus.Success then
    -- Obtenha os pontos de caminho
    waypoints = path:GetWaypoints()
    -- Detectar se o caminho se torna bloqueado
    blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
    -- Verifique se o obstáculo está mais abaixo do caminho
    if blockedWaypointIndex >= nextWaypointIndex then
    -- Pare de detectar bloqueio de caminho até que o caminho seja recomputado
    blockedConnection:Disconnect()
    -- Chame a função para recalcular o novo caminho
    followPath(destination)
    end
    end)
    -- Detectar quando o movimento para o próximo waypoint estiver completo
    if not reachedConnection then
    reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
    if reached and nextWaypointIndex < #waypoints then
    -- Aumentar o índice de pontos de caminho e mover para o próximo pontos de caminho
    nextWaypointIndex += 1
    -- Use o barco se a etiqueta de destino for "UseBoat"; caso contrário, mova-se para o próximo destino
    if waypoints[nextWaypointIndex].Label == "UseBoat" then
    useBoat()
    else
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    else
    reachedConnection:Disconnect()
    blockedConnection:Disconnect()
    end
    end)
    end
    -- Inicialmente mova-se para o segundo waypoint (o primeiro waypoint é o iniciardo caminho; pule-o)
    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()
    -- Comece a mover o barco se o agente estiver sentado
    if humanoid.Sit then
    task.wait(1)
    boat.CylindricalConstraint.Velocity = 5
    end
    -- Detectar posição de restrição em relação à ilha
    local boatPositionConnection
    boatPositionConnection = RunService.PostSimulation:Connect(function()
    -- Pare o barco quando ao lado da ilha
    if boat.CylindricalConstraint.CurrentPosition >= 94 then
    boatPositionConnection:Disconnect()
    boat.CylindricalConstraint.Velocity = 0
    task.wait(1)
    -- Desinstale o agente e continue para o destino
    humanoid.Sit = false
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    end)
    end)
    end
    followPath(TEST_DESTINATION)

Compatibilidade de streaming

O streaming de instância na experiência é uma poderosa funcionalidade que carrega e descarrega dinamicamente conteúdo 3D enquanto um personagem do jogador se move ao redor do mundo.À medida que exploram o espaço 3D, novos subconjuntos do fluxo de espaço são transmitidos para o dispositivo deles e alguns dos subconjuntos existentes podem ser transmitidos.

Considere as seguintes melhores práticas para usar PathfindingService em experiências habilitadas para streaming:

  • Streaming pode bloquear ou desbloquear um caminho dado à medida que um personagem se move ao longo dele.Por exemplo, enquanto um personagem corre através de uma floresta, uma árvore pode aparecer em algum lugar à frente deles e obstruir o caminho.Para que a pesquisa de caminho funcione sem problemas com streaming, é altamente recomendável que você use a técnica lidar com caminhos bloqueados e re compute o caminho quando necessário.

  • Uma abordagem comum na busca de caminho é usar as coordenadas de objetos existentes para cálculo , como definir um destino de caminho para a posição de um modelo de Baú do Tesouro existente no mundo.Essa abordagem é totalmente compatível com o lado do servidor Scripts pois o servidor tem visão completa do mundo o tempo todo, mas LocalScripts e ModuleScripts que são executados no cliente podem falhar se tentarem calcular um caminho para um objeto que não está sendo transmitido.

    Para abordar esse problema, considere definir o destino para a posição de um BasePart dentro de um modelo persistente persistente.Modelos persistentes carregam logo após o jogador se juntar e eles nunca são transmitidos, então um script do lado do cliente pode se conectar ao evento PersistentLoaded e acessar seguramente o modelo para criar pontos de caminho após o evento disparar.