Rilevamento del percorso del personaggio

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Pathfinding è il processo di spostamento di un personaggio lungo un percorso logico per raggiungere una destinazione, evitando gli ostacoli e (opzionalmente) materiali pericolosi o regioni definite.

Visualizzazione della navigazione

Per aiutare con la creazione di una mappa di pathfinding e debugging, Studio può rendere una mappa di navigazione e modificatore etichetta. Per abilitare questi, attiva Navigation Mesh e 2> Pathfinding Modifier2> dalla visualizzazione 5>Opzioni5> nella parte superiore destra del 3D finestra.

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

Con Navigation mesh abilitato, le aree colorate mostrano dove un personaggio potrebbe camminare o nuotare, mentre le aree non colorate sono bloccate. Le piccole frecce indicano le aree che un personaggio cercherà di raggiungere facendo un salto, supponendo che tu abbia impostato AgentCanJump a true quando 1> crei la strada1> .

Navigation mesh showing in Studio

Con modificatori di Pathfinding abilitati, le etichettature del testo indicano materiali e regioni specifici che vengono presi in considerazione quando si utilizzano modificatori di 1>Pathfinding1> .

Navigation labels showing on navigation mesh

Limitazioni conosciute

Le funzionalità di Pathfinding hanno limitazioni specifiche per garantire un elaborazione efficiente e le Prestazioneottimali.

Limite di posizionamento verticale

I calcoli di Pathfinding considerano solo parti all'interno di determinati limiti verticali:

  • Lower Boundary — Parts with a bottom Y coordinate less than -65,536 studs are ignored.
  • Upper Boundary — Parts with a top Y coordinate exceeding 65,536 studs are ignored.
  • Spannazione verticale — La distanza verticale dalla parte inferiore Y coordina alla parte superiore Y deve non superare 65.536 studs; altrimenti, il sistema di pathfinding ignorerà queste parti durante il calcolo di pathfinding.

Ricerca della limitazione della distanza

La distanza di linea di visione diretta per la creazione di percorsi dal punto di partenza al punto di destinazione non deve essere superiore a 3.000 studs. L'eccedenza di questa distanza risulterà in uno Statodi NoPath .

Creazione di percorsi

La creazione del percorso è iniziata attraverso PathfindingService e la sua funzione CreatePath() .

Script locale

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

CreatePath() accetta una tabella di parametri opzionali che regola il modo in cui il personaggio (agente) si muove lungo la strada.

ChiaveDescrizioneTipoPredefinito
AgentRadiusRaggio dell'agente, in studs. Utile per determinare la separazione minima da gli ostacoli.integro2
AgentHeightAltezza dell'agente, in studs. Spazio vuoto minore di questo valore, come lo spazio sotto le scale, sarà contrassegnato come non attraversabile.integro5
AgentCanJumpDetermina se è permesso saltare durante la creazione del percorso.booleanotrue
AgentCanClimbDetermina se è permesso di arrampicare TrussParts durante la creazione del percorso.booleanofalse
WaypointSpacingSpaziatura tra i punti di interruzione in path. Se impostato su math.huge, non ci saranno punti di interruzione intermedi.number4
CostsTavola dei materiali o definiti PathfindingModifiers e il loro costo per il passaggio. Utile per rendere l'agente preferire determinati materiali/regioni rispetto ad altri. Vedi modificatori per i dettagli.tabellanil
Script locale

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

Nota che l'agente può salire TrussParts durante la ricerca del percorso supponendo che tu abbia impostato AgentCanClimb su true quando crei la ricerca del percorso e nulla blocca l'agente dalla strada

Path going up a climbable TrussPart ladder
Script locale - Percorso di salita

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath({
AgentCanClimb = true,
Costs = {
Climb = 2 -- Costo della strada di arrampicata; il valore predefinito è 1
}
})

Spostamento lungo le vie

Questa sezione usa lo script di pathfinding seguente per il personaggio del Giocatore. Per testare mentre si legge:

  1. Copia il codice in un LocalScript dentro StarterCharacterScripts .
  2. Modifica la linea 11 a una destinazione Vector3 che il personaggio del giocatore può raggiungere.
  3. Passa attraverso le seguenti sezioni per saperne di più sulla calcolazione del percorso e sulla movimentazione del personaggio.
Script locale - Trovare il percorso del personaggio

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)
-- Calcola il percorso
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Ottieni i punti di riferimento
waypoints = path:GetWaypoints()
-- Detecta se il percorso diventa bloccato
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Controlla se l'ostacolo è ulteriormente in discesa
if blockedWaypointIndex >= nextWaypointIndex then
-- Interrompi il rilevamento del blocco di percorso fino a quando il percorso non viene ri-calcolato
blockedConnection:Disconnect()
-- Chiama la funzione per calcolare un nuovo percorso
followPath(destination)
end
end)
-- Rileva quando il movimento verso il prossimo punto di interesse è completato
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumenta l'indice di waypoint e sposta al prossimo waypoint
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inizialmente spostare al secondo punto (il primo punto è l'Iniziare, cominciaredel percorso; saltare)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)

Calcolo del Path

Dopo aver creato un percorso valido con CreatePath() , deve essere calcolato chiamando Path:ComputeAsync() con un 1> Datatype.Vector31> per entrambi il punto di partenza e la destinazione.

Script locale - Trovare il percorso del personaggio

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

Ottenere Waypoints

Una volta che il Path è stato calcolato, contiene una serie di waypoint che tracciano il percorso dall'inizio alla Terminare. Questi punti possono essere raccolti con la funzione Path:GetWaypoints().

Script locale - Trovare il percorso del personaggio

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)
-- Calcola il percorso
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Ottieni i punti di riferimento
waypoints = path:GetWaypoints()
end
end
Waypoints indicated across computed path
I Waypoints mostrati attraverso il percorso calcolato

Movimento del percorso

Ogni punto di interesse consiste in due posizione ( Vector3 ) e in una azione ( 2> Class.Humanoid:MoveTo

Script locale - Trovare il percorso del personaggio

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)
-- Calcola il percorso
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Ottieni i punti di riferimento
waypoints = path:GetWaypoints()
-- Detecta se il percorso diventa bloccato
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Controlla se l'ostacolo è ulteriormente in discesa
if blockedWaypointIndex >= nextWaypointIndex then
-- Interrompi il rilevamento del blocco di percorso fino a quando il percorso non viene ri-calcolato
blockedConnection:Disconnect()
-- Chiama la funzione per calcolare un nuovo percorso
followPath(destination)
end
end)
-- Rileva quando il movimento verso il prossimo punto di interesse è completato
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumenta l'indice di waypoint e sposta al prossimo waypoint
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inizialmente spostare al secondo punto (il primo punto è l'Iniziare, cominciaredel percorso; saltare)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end

Maneggamento delle vie bloccate

Molti mondi Roblox sono dinamici; le parti possono muoversi o cadere e i pavimenti possono crollare. Ciò può bloccare un percorso calcolato e impedire al personaggio di raggiungere la sua destinazione. Per gestire questo, puoi connettere l'evento Path.Blocked e ricalcolare il percorso intorno a ciò che ha bloccato.

Script locale - Trovare il percorso del personaggio

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)
-- Calcola il percorso
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Ottieni i punti di riferimento
waypoints = path:GetWaypoints()
-- Detecta se il percorso diventa bloccato
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Controlla se l'ostacolo è ulteriormente in discesa
if blockedWaypointIndex >= nextWaypointIndex then
-- Interrompi il rilevamento del blocco di percorso fino a quando il percorso non viene ri-calcolato
blockedConnection:Disconnect()
-- Chiama la funzione per calcolare un nuovo percorso
followPath(destination)
end
end)
end
end

Modificatori per il pathfinding

Per impostazione predefinita, Path:ComputeAsync() restituisce il percorso più breve tra il punto di partenza e la destinazione, con l'eccezione che cerca di evitare i salti. Ciò sembra non naturale in alcune situazioni, ad esempio, un percorso può andare attraverso l'acqua invece che attraverso un ponte vicino, semplicemente perché il percorso attraverso l'acqua è più breve geometricalmente.

Two paths indicated with the shorter path not necessarily more logical

Per ottimizzare ulteriormente la ricerca del percorso, puoi implementare modificatori di percorso per calcolare percorsi più intelligenti su varie 材料 , intorno a regioni definite o attraverso 2>ostacoli2> .

Impostazione dei costi materiali

Quando lavori con Terrain e BasePart materiali, puoi includere una tabella Costs all'interno di 1> Class.PathfindingService:CreatePath()|CreatePath()1> per rendere alcuni materiali più traversab

Le chiavi nella tabella Costs devono essere nomi di stringa rappresentanti Enum.Material nomi, ad esempio Water per 1> Enum.Material.Water1> .

Script locale - Trovare il percorso del personaggio

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

Lavorare con le regioni

In alcuni casi, prendere materiale di preferenza non è abbastanza. Ad esempio, potresti voler che i personaggi evitino una regione definita , indipendentemente dai materiali sotto il piede. Questo può essere raggiunto aggiungendo un oggetto PathfindingModifier a una parte.

  1. Crea un Class.BasePart.Anchored|Anchored parte intorno alla regione pericolosa e imposta la sua proprietà Class.BasePart.CanCollide|CanCollide su falsa.

    Anchored part defining a region to apply a pathfinding modifier to
  2. Inserisci una PathfindingModifier istanza sulla parte, individua la sua ProprietàLabel e assegna un nome significativo come DangerZone .

    PathfindingModifier instance with Label property set to DangerZone
  3. Includi una tabella Costs all'interno di CreatePath() che contiene un valore corrispondente e un valore numerico associato. Un modificatore può essere definito come non trasparente impostando il suo valore su math.huge .

    Script locale - Trovare il percorso del personaggio

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

Ignorare gli ostacoli

In alcuni casi, è utile percorrere i blocchi di solido come se non esistessero. Ciò ti consente di calcolare un percorso attraverso blocchi fisici specifici, invece della perdita di calcolo.

  1. Crea un Anchored part around the object and set its CanCollide property to false .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Inserisci un'istanza PathfindingModifier sulla parte e abilita la sua ProprietàPassThrough .

    PathfindingModifier instance with PassThrough property enabled

    Ora, quando un percorso viene calcolato dall'NPC zombie al personaggio del giocatore, il percorso si estende oltre la porta e puoi richiedere al zombie di attraversarla. Anche se il zombie non è in grado di aprire la porta, reagisce come se "ascoltasse" il personaggio dietro la porta.

    Zombie NPC path passing through the previously blocking door

Percorsi di ricerca della strada

A volte è necessario trovare un percorso attraverso uno spazio che non può essere normalmente attraversato, come attraverso uno scogliera, e eseguire un'azione personalizzata per raggiungere il prossimo punto di interruzione. Questo può essere raggiunto attraverso l'oggetto PathfindingLink.

Usando l'esempio dell'isola sopra, puoi far usare l'agente una barca invece di camminare attraverso tutti i ponti.

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

Per creare un PathfindingLink utilizzando questo esempio:

  1. Per assistere alla visualizzazione e al debug, attiva Pathfinding link dai widget Opzioni di visualizzazione nell'angolo in alto a destra della finestra3D.

  2. Crea due Attachments , uno sul sedile della barca e uno vicino al punto d'atterraggio della barca.

    Attachments created for pathfinding link's start and end
  3. Crea un oggetto PathfindingLink nell'area di lavoro, quindi assegna le sue proprietà Attachment0 e Attachment1 alle rispettive proprietà di avvio e fine.

    Attachment0/Attachment1 properties of a PathfindingLink PathfindingLink visualized in the 3D world
  4. Assign a meaningful name like UseBoat to its Label Proprietà. This name is used as a flag in the pathfinding script to trigger a custom action when the agent reaches the starting link point.

    Label property specified for PathfindingLink
  5. Includi una tabella Costs all'interno di CreatePath() che contiene sia una chiave Water che una chiave personalizzata corrispondente alla proprietà 1> Class.PathfindingLink.Label|Label1> . Assegna la chiave personalizzata un valore inferiore a 4> Water4> .

    Script locale - Trovare il percorso del personaggio

    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. Nell'evento che si attiva quando viene raggiunto un waypoint, aggiungi un check personalizzato per il modificatore Label e prendi un'azione diversa da Humanoid:MoveTo() — in questo caso, chiamando una funzione per sedere l'agente nella barca, muovi la barca attraverso l'acqua e continua il percorso dell'agente all'arrivo sull'is

    Script locale - Trovare il percorso del personaggio

    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)
    -- Calcola il percorso
    local success, errorMessage = pcall(function()
    path:ComputeAsync(character.PrimaryPart.Position, destination)
    end)
    if success and path.Status == Enum.PathStatus.Success then
    -- Ottieni i punti di riferimento
    waypoints = path:GetWaypoints()
    -- Detecta se il percorso diventa bloccato
    blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
    -- Controlla se l'ostacolo è ulteriormente in discesa
    if blockedWaypointIndex >= nextWaypointIndex then
    -- Interrompi il rilevamento del blocco di percorso fino a quando il percorso non viene ri-calcolato
    blockedConnection:Disconnect()
    -- Chiama la funzione per calcolare un nuovo percorso
    followPath(destination)
    end
    end)
    -- Rileva quando il movimento verso il prossimo punto di interesse è completato
    if not reachedConnection then
    reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
    if reached and nextWaypointIndex < #waypoints then
    -- Aumenta l'indice di waypoint e sposta al prossimo waypoint
    nextWaypointIndex += 1
    -- Usa la barca se la etichetta del punto d'intersezione è "UsaBarca"; altrimenti sposta al prossimo punto d'intersezione
    if waypoints[nextWaypointIndex].Label == "UseBoat" then
    useBoat()
    else
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    else
    reachedConnection:Disconnect()
    blockedConnection:Disconnect()
    end
    end)
    end
    -- Inizialmente spostare al secondo punto (il primo punto è l'Iniziare, cominciaredel percorso; saltare)
    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()
    -- Inizia a muoverti la barca se l'agente è seduto
    if humanoid.Sit then
    task.wait(1)
    boat.CylindricalConstraint.Velocity = 5
    end
    -- Individua la posizione di vincolo in relazione all'isola
    local boatPositionConnection
    boatPositionConnection = RunService.PostSimulation:Connect(function()
    -- Fai salire la barca quando sei vicino all'isola
    if boat.CylindricalConstraint.CurrentPosition >= 94 then
    boatPositionConnection:Disconnect()
    boat.CylindricalConstraint.Velocity = 0
    task.wait(1)
    -- Sganciare l'agente e continuare la destinazione
    humanoid.Sit = false
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    end)
    end)
    end
    followPath(TEST_DESTINATION)

compatibilità con gli stream

In-experience streaming dell'istanza è una potente funzione che carica e scarica dinamicamente il contenuto 3D come un personaggio del Giocatoresi muove nel Mondo. Mentre esplorano lo Spazio3D, nuovi subset dello stream spazio al loro dispositivo e alcuni dei subset esistenti potrebbero stream out.

Considera le seguenti migliori pratiche per l'uso di PathfindingService in esperienze abilitate in streaming:

  • Il streaming può bloccare o unbloccare un percorso specifico mentre un personaggio lo attraversa. Ad esempio, mentre un personaggio corre attraverso una foresta, un albero potrebbe stream in qualche punto in avanti di loro e interrompere il percorso. Per rendere il pathfinding perfettamente funzionante con lo streaming, è altamente raccomandato di utilizzare la tecnica Gestire i percorsi bloccati e ricomputare il percorso quando necessario.

  • Un approccio comune in pathfinding è di utilizzare i coordinati di oggetti esistenti per calcolare , come impostare una destinazione di percorso alla posizione di un modello TreasureChest esistente nel Mondo

    Per affrontare questo problema, considera di impostare la destinazione nella posizione di un BasePart all'interno di un modello persistente . I modelli persistenti vengono caricati presto dopo che il giocatore si unisce e non vengono mai streamed, quindi uno script lato client può connettersi all'evento PersistentLoaded e accedere in sicurezza al modello per