Ricerca del percorso del personaggio

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

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

Visualizzazione della navigazione

Per aiutare con la ricerca del percorso e il debugging, Studio può rendere una griglia di navigazione e modificatori etichette.Per abilitarli, attiva mesh di navigazione e modificatori di percorso dalla finestra Opzioni di visualizzazione nell'angolo in alto a destra della vista 3D.

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

Con mesh di navigazione abilitata, 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 saltando, supponendo che tu abbia impostato AgentCanJump su true quando crei il percorso .

Navigation mesh showing in Studio

Con modificatori di ricerca di percorso abilitati, le etichette di testo indicano materiali e regioni specifici che vengono presi in considerazione quando si utilizzano modificatori di ricerca di percorso.

Navigation labels showing on navigation mesh

Limiti noti

Le funzionalità di trova percorso hanno limitazioni specifiche per garantire un'efficace elaborazione e Prestazioneottimali.

Limite di posizionamento verticale

I calcoli di ricerca del percorso considerano solo le parti all'interno di determinati confini verticali:

  • Sottolimitazione — Le parti con una coordinata inferiore Y a meno di -65,536 stud sono ignorate.
  • Limite superiore — Le parti con una coordinata superiore Y che supera 65,536 studs vengono ignorate.
  • Intervallo verticale — La distanza verticale dal fondo della parte più bassa Y alla coordinata della parte più alta Y non deve superare 65,536 borchie; altrimenti, il sistema di ricerca del percorso ignorerà quelle parti durante il calcolo della ricerca del percorso.

Limite di distanza di ricerca

La distanza lineare diretta per la ricerca del percorso dall'inizio al punto di arrivo non deve superare 3.000 studs.Superare questa distanza comporterà uno StatoNoPath di >.

Crea sentieri

La ricerca del percorso viene inizializzata attraverso PathfindingService e la sua funzione CreatePath().

Script locale

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

CreatePath() accetta una tabella opzionale di parametri che ottimizza il modo in cui il personaggio (agente) si muove lungo il percorso.

ChiaveDescrizioneTipoBasilare
AgentRadiusRaggio dell'agente, in studs. Utile per determinare la separazione minima dagli ostacoli.integro2
AgentHeightAltezza dell'agente, in studs. Lo spazio vuoto più piccolo di questo valore, come lo spazio sotto le scale, sarà contrassegnato come non percorribile.integro5
AgentCanJumpDetermina se è consentito saltare durante la ricerca del percorso.booleanotrue
AgentCanClimbDetermina se è consentito salire TrussParts durante la ricerca del percorso.booleanofalse
WaypointSpacingSpaziatura tra i punti di percorso intermedi nel percorso. Se impostato su math.huge, non ci saranno punti di percorso intermedi.numbero4
CostsTabella dei materiali o definita PathfindingModifiers e il loro costo per la traversal.Utile per far preferire all'agente determinati materiali/regioni rispetto ad altri.Vedi modificatori per i dettagli.tavolanil
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 imposti AgentCanClimb a true quando crei il percorso e nulla blocca l'agente dal percorso di salita della truss.Un percorso salibile ha il Etichetta di salita e il costo per un percorso salibile è 1 per impostazione predefinita.

Path going up a climbable TrussPart ladder
Script locale - Pathdi arrampicata sul truss

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

Muoviti lungo i percorsi

Questa sezione utilizza lo script di ricerca del percorso seguente per il personaggio del Giocatore. Per testare mentre si legge:

  1. Copia il codice in un LocalScript entro StarterCharacterScripts .
  2. Imposta la variabile TEST_DESTINATION a una destinazione Vector3 nel tuo mondo 3D a cui il personaggio del giocatore può raggiungere.
  3. Procedi attraverso le seguenti sezioni per imparare a conoscere la calcolata del percorso e il movimento dei personaggi.
Script locale - Trova il percorso dei personaggi

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)
-- 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 percorso
waypoints = path:GetWaypoints()
-- Rileva se il percorso diventa bloccato
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Verifica se l'ostacolo è più in basso sul percorso
if blockedWaypointIndex >= nextWaypointIndex then
-- Interrompi il rilevamento del blocco del percorso fino a quando il percorso non viene ricomputato
blockedConnection:Disconnect()
-- Chiama la funzione per ricomputare il nuovo percorso
followPath(destination)
end
end)
-- Rileva quando il movimento al punto di destinazione successivo è completo
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumenta l'indice dei punti di percorso e muoviti al prossimo punto di percorso
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inizialmente spostati al secondo punto di passaggio (il primo punto di passaggio è l'Iniziare, cominciaredel percorso; saltalo)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)

Calcola il percorso

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

Script locale - Trova il percorso dei personaggi

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

Ottieni waypoint

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

Script locale - Trova il percorso dei personaggi

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)
-- 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 percorso
waypoints = path:GetWaypoints()
end
end
Waypoints indicated across computed path
Punti di percorso indicati attraverso il percorso calcolato

Movimento del percorso

Ogni punto di riferimento consiste in entrambi una posizione ( ) e un'azione ( ) .Per spostare un personaggio che contiene un Humanoid , come un tipico personaggio Roblox, il modo più semplice è chiamare Humanoid:MoveTo() da punto di percorso a punto di percorso, utilizzando l'evento MoveToFinished per rilevare quando il personaggio raggiunge ogni punto di percorso.

Script locale - Trova il percorso dei personaggi

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)
-- 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 percorso
waypoints = path:GetWaypoints()
-- Rileva se il percorso diventa bloccato
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Verifica se l'ostacolo è più in basso sul percorso
if blockedWaypointIndex >= nextWaypointIndex then
-- Interrompi il rilevamento del blocco del percorso fino a quando il percorso non viene ricomputato
blockedConnection:Disconnect()
-- Chiama la funzione per ricomputare il nuovo percorso
followPath(destination)
end
end)
-- Rileva quando il movimento al punto di destinazione successivo è completo
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Aumenta l'indice dei punti di percorso e muoviti al prossimo punto di percorso
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Inizialmente spostati al secondo punto di passaggio (il primo punto di passaggio è l'Iniziare, cominciaredel percorso; saltalo)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end

Maneggiare percorsi bloccati

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

Script locale - Trova il percorso dei personaggi

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)
-- 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 percorso
waypoints = path:GetWaypoints()
-- Rileva se il percorso diventa bloccato
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Verifica se l'ostacolo è più in basso sul percorso
if blockedWaypointIndex >= nextWaypointIndex then
-- Interrompi il rilevamento del blocco del percorso fino a quando il percorso non viene ricomputato
blockedConnection:Disconnect()
-- Chiama la funzione per ricomputare il nuovo percorso
followPath(destination)
end
end)
end
end

Modificatori di pathfinding

Per impostazione predefinita, restituisce il percorso più breve tra il punto di partenza e la destinazione, con l'eccezione che tenta di evitare i salti.Questo sembra innaturale in alcune situazioni - per esempio, un percorso può passare attraverso l'acqua piuttosto che su un ponte vicino semplicemente perché il percorso attraverso l'acqua è geometricamente più breve.

Two paths indicated with the shorter path not necessarily more logical

Per ottimizzare ulteriormente la ricerca del percorso, puoi implementare modificatori di ricerca del percorso per calcolare percorsi più intelligenti attraverso vari materiali, intorno a regioni definite, o attraverso ostacles.

Imposta i costi del materiale

Lavorando con Terrain e BasePart materiali, puoi includere una tabella Costs all'interno di CreatePath() per rendere alcuni materiali più trasponibili di altri.Tutti i materiali hanno un costo predefinito di 1 e qualsiasi materiale può essere definito non attraversabile impostando il suo valore a math.huge .

Le chiavi nella tabella Costs dovrebbero essere nomi di stringa che rappresentano Enum.Material nomi, ad esempio Water per Enum.Material.Water .

Script locale - Trova il percorso dei personaggi

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

Lavora con le regioni

In alcuni casi, preferenza del materiale non è sufficiente.Ad esempio, potresti volere che i personaggi evitino una regione definita , indipendentemente dai materiali sottostanti.Questo può essere ottenuto aggiungendo un oggetto PathfindingModifier a una parte.

  1. Crea una parte Anchored attorno alla regione pericolosa e imposta la sua proprietà CanCollide a falso .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Inserisci un'istanza PathfindingModifier su 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() contenente una chiave corrispondente e un valore numerico associato.Un modificatore può essere definito non attraversabile impostando il suo valore a math.huge .

    Script locale - Trova il percorso dei personaggi

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

Ignora gli ostacoli

In alcuni casi, è utile trovare il percorso attraverso ostacoli solidi come se non esistessero.Questo ti consente di calcolare un percorso attraverso blocchi fisici specifici, rispetto alla mancata esecuzione della computazione.

  1. Crea una parte Anchored attorno all'oggetto e imposta la sua proprietà CanCollide a falso .

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

    PathfindingModifier instance with PassThrough property enabled

    Ora, quando un percorso viene calcolato dal NPC zombie al personaggio del giocatore, il percorso si estende oltre la porta e puoi richiedere allo zombie di attraversarlo.Anche se lo zombie non è in grado di aprire la porta, reagisce come se "sentisse" il personaggio dietro la porta.

    Zombie NPC path passing through the previously blocking door

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

Usando l'esempio dell'isola dall'alto, puoi far usare all'agente una barca invece di camminare su 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 con la visualizzazione e il debug, attiva collegamenti di ricerca del percorso dal 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 di 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 allegature iniziali e finali.

    Attachment0/Attachment1 properties of a PathfindingLink PathfindingLink visualized in the 3D world
  4. Assegna un nome significativo come UseBoat alla sua ProprietàLabel.Questo nome viene utilizzato come bandiera nello script di ricerca del percorso per attivare un'azione personalizzata quando l'agente raggiunge il punto di collegamento iniziale.

    Label property specified for PathfindingLink
  5. Includi una tabella contenente sia una chiave e una chiave personalizzata corrispondente al nome della proprietà .Assegna alla chiave personalizzata un valore più basso di Water .

    Script locale - Trova il percorso dei personaggi

    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. Nell'evento che si attiva quando un punto di passaggio viene raggiunto, aggiungi un controllo personalizzato per il nome del modificatore Label e intraprendi un'azione diversa da quella di Humanoid:MoveTo() — in questo caso, chiama una funzione per sedere l'agente nella barca, muoverla attraverso l'acqua e continuare il percorso dell'agente all'arrivo sull'isola di destinazione.

    Script locale - Trova il percorso dei personaggi

    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)
    -- 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 percorso
    waypoints = path:GetWaypoints()
    -- Rileva se il percorso diventa bloccato
    blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
    -- Verifica se l'ostacolo è più in basso sul percorso
    if blockedWaypointIndex >= nextWaypointIndex then
    -- Interrompi il rilevamento del blocco del percorso fino a quando il percorso non viene ricomputato
    blockedConnection:Disconnect()
    -- Chiama la funzione per ricomputare il nuovo percorso
    followPath(destination)
    end
    end)
    -- Rileva quando il movimento al punto di destinazione successivo è completo
    if not reachedConnection then
    reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
    if reached and nextWaypointIndex < #waypoints then
    -- Aumenta l'indice dei punti di percorso e muoviti al prossimo punto di percorso
    nextWaypointIndex += 1
    -- Usa la barca se l'etichetta waypoint è "UseBoat"; altrimenti spostati al prossimo waypoint
    if waypoints[nextWaypointIndex].Label == "UseBoat" then
    useBoat()
    else
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    else
    reachedConnection:Disconnect()
    blockedConnection:Disconnect()
    end
    end)
    end
    -- Inizialmente spostati al secondo punto di passaggio (il primo punto di passaggio è l'Iniziare, cominciaredel percorso; saltalo)
    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()
    -- Avvia la barca in movimento se l'agente è seduto
    if humanoid.Sit then
    task.wait(1)
    boat.CylindricalConstraint.Velocity = 5
    end
    -- Rileva la posizione della restrizione in relazione all'isola
    local boatPositionConnection
    boatPositionConnection = RunService.PostSimulation:Connect(function()
    -- Fermare la barca quando accanto all'isola
    if boat.CylindricalConstraint.CurrentPosition >= 94 then
    boatPositionConnection:Disconnect()
    boat.CylindricalConstraint.Velocity = 0
    task.wait(1)
    -- Siediti l'agente e continua alla destinazione
    humanoid.Sit = false
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    end)
    end)
    end
    followPath(TEST_DESTINATION)

Compatibilità di streaming

Lo streaming dell'istanza in-experience in tempo reale è una potente funzione che carica e scarica dinamicamente il contenuto 3D mentre un personaggio del Giocatoresi muove in tutto il Mondo.Mentre esplorano lo Spazio3D, nuovi sottinsiemi dello stream spaziale vengono inviati al loro dispositivo e alcuni dei sottinsiemi esistenti potrebbero essere trasmessi.

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

  • Lo streaming può bloccare o sbloccare un percorso dato mentre un personaggio lo percorre.Ad esempio, mentre un personaggio attraversa una foresta, un albero potrebbe streamare in qualche posto prima di loro e ostacolare il percorso.Per rendere il lavoro di ricerca del percorso senza soluzione di continuità con lo streaming, è altamente raccomandato utilizzare la tecnica gestire i percorsi bloccati e ricomputare il percorso quando necessario.

  • Un approccio comune nel trovare il percorso è quello di utilizzare le coordinate di oggetti esistenti per calcolo, come impostare una destinazione di percorso alla posizione di un modello Cassetta del Tesoro esistente nel Mondo.Questo approccio è pienamente compatibile con il lato server Scripts poiché il server ha una visione completa del mondo in ogni momento, ma LocalScripts e ModuleScripts quelli che si eseguono sul client possono fallire se tentano di calcolare un percorso verso un oggetto che non viene trasmesso in.

    Per risolvere questo problema, considera di impostare la destinazione alla posizione di un BasePart all'interno di un modello persistente persistente.I modelli persistenti si caricano poco dopo che il giocatore si unisce e non vengono mai trasmessi, quindi uno script lato client può connettersi all'evento PersistentLoaded e accedere in sicurezza al modello per creare punti di percorso dopo l'evento.