Penemuan Jalur adalah proses memindahkan karakter di sepanjang jalur logis untuk mencapai tujuan, menghindari hambatan dan (opsional) bahan berbahaya atau wilayah yang didefinisikan.
Visualisasi navigasi
Untuk membantu dengan tata letak pencarian jalur dan debugging, Studio dapat menyajikan mesh navigasi dan label modifikasi.Untuk mengaktifkannya, beralih pada mesh navigasi dan modifikasi pencarian jalur dari widget Opsi visualisasi di sudut kanan atas tampilan 3D.

Dengan mesh navigasi diaktifkan, area berwarna menunjukkan di mana karakter bisa berjalan atau berenang, sementara area berwarna tidak diblokir.Panah kecil menunjukkan area yang akan dicapai karakter dengan melompat, asumsi Anda mengatur AgentCanJump ke true ketika membuat jalur .

Dengan modifikasi penemuan jalur diaktifkan, label teks menunjukkan materi dan wilayah tertentu yang dipertimbangkan saat menggunakan modifikasi penemuan jalur .

Kelebatan yang dikenal
Fitur penemuan jalur memiliki batasan khusus untuk memastikan pemrosesan yang pelaksanaandan kinerja optimal.
Batas penempatan vertikal
Perhitungan penemuan jalur hanya mempertimbangkan bagian dalam batas vertikal tertentu:
- Batas Bawah — Bagian dengan koordinat bawah Y kurang dari -65,536 stud diabaikan.
- Batas Atas — Bagian dengan koordinat teratas Y melebihi 65.536 kancing diabaikan.
- Jangkauan Vertikal — Jarak vertikal dari bagian terendah ke bawah Y koordinat ke bagian tertinggi Y koordinat tidak boleh melebihi 65,536 stud; jika tidak, sistem penemuan jalur akan mengabaikan bagian-bagian tersebut selama penghitungan penemuan jalur.
Pembatasan jarak pencarian
Jarak pandang langsung untuk menemukan jalur dari awal sampai titik akhir tidak boleh melebihi 3.000 stud.Melebihi jarak ini akan menyebabkan status NoPath .
Buat jalur
Penemuan jalur dimulai melalui PathfindingService dan fungsi CreatePath() nya.
Skrip Lokal
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath()
CreatePath() menerima tabel opsional parameter yang menyesuaikan bagaimana karakter (agen) bergerak di sepanjang jalur.
Kunci | Deskripsi | Jenis | Standar |
---|---|---|---|
AgentRadius | Radius agen, dalam stud. Berguna untuk menentukan jarak minimum dari penghalang. | integer | 2 |
AgentHeight | Tinggi agen, dalam stud. Ruang kosong yang lebih kecil dari nilai ini, seperti ruang di bawah tangga, akan ditandai sebagai tidak dapat dilalui. | integer | 5 |
AgentCanJump | Menentukan apakah melompat selama pencarian jalur diizinkan. | boolean | true |
AgentCanClimb | Menentukan apakah pendakian TrussParts selama pencarian jalur diizinkan. | boolean | false |
WaypointSpacing | Jarak antara titik jalan tengah di jalur. Jika diatur ke math.huge, tidak akan ada titik jalan tengah. | angka | 4 |
Costs | Tabel materi atau didefinisikan PathfindingModifiers dan biaya untuk melintasi.Berguna untuk membuat agen lebih memilih materi/wilayah tertentu daripada yang lain.Lihat modifikator untuk rincian. | meja | nil |
Skrip Lokal
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath({AgentRadius = 3,AgentHeight = 6,AgentCanJump = false,Costs = {Water = 20}})
Perhatikan bahwa agen dapat menaiki TrussParts selama pencarian jalur dengan asumsi Anda mengatur AgentCanClimb ke true ketika membuat jalur dan tidak ada yang memblokir agen dari jalur panjat truss.Jalur yang dapat didaki memiliki label Naik dan biaya untuk jalur yang dapat didaki adalah 1 secara default.

Skrip Lokal - Jalur Pendakian Truss
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath({AgentCanClimb = true,Costs = {Climb = 2 -- Biaya dari jalur pendakian; default adalah 1}})
Pindah di sepanjang jalur
Bagian ini menggunakan skrip penemuan jalur berikut untuk karakter pemain. Untuk diuji saat membaca:
- Salin kode ke dalam LocalScript dalam StarterCharacterScripts .
- Tetapkan variabel TEST_DESTINATION untuk tujuan Vector3 di dunia 3D Anda yang dapat dicapai karakter pemain.
- Lanjutkan melalui bagian berikut untuk mempelajari tentang perhitungan jalur dan gerakan karakter.
Skrip Lokal - Pencarian Karakter
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)
-- Hitung jalur
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalur cara
waypoints = path:GetWaypoints()
-- Deteksi apakah jalur menjadi diblokir
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Periksa apakah rintangan berada lebih jauh di jalan
if blockedWaypointIndex >= nextWaypointIndex then
-- Hentikan pendeteksi blok jalur sampai jalur dihitung ulang
blockedConnection:Disconnect()
-- Fungsi panggil untuk menghitung ulang jalur baru
followPath(destination)
end
end)
-- Deteksi ketika gerakan ke waypoint berikutnya selesai
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Tingkatkan indeks waypoint dan pindah ke waypoint berikutnya
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Pada awalnya pindah ke titik jalur kedua (titik jalur pertama adalah mulaijalur; lewati)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)
Hitung jalur
Setelah Anda membuat jalur yang valid dengan CreatePath() , itu harus dihitung dengan memanggil Path:ComputeAsync() dengan Vector3 untuk titik awal dan tujuan.
Skrip Lokal - Pencarian Karakter
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)
-- Hitung jalur
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
end

Dapatkan waypoint
Setelah Path dihitung, ia akan berisi serangkaian waypoint yang melacak jalur dari awal sampai akhiri.Poin-poin ini dapat dikumpulkan dengan fungsi Path:GetWaypoints() .
Skrip Lokal - Pencarian Karakter
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)
-- Hitung jalur
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalur cara
waypoints = path:GetWaypoints()
end
end

Gerakan jalur
Setiap waypoint terdiri dari kedua posisi () dan tindakan () .Untuk memindahkan karakter yang berisi Humanoid , seperti karakter Roblox tipikal, cara termudah adalah memanggil Humanoid:MoveTo() dari waypoint ke waypoint, menggunakan acara MoveToFinished untuk mendeteksi ketika karakter mencapai setiap waypoint.
Skrip Lokal - Pencarian Karakter
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)
-- Hitung jalur
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalur cara
waypoints = path:GetWaypoints()
-- Deteksi apakah jalur menjadi diblokir
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Periksa apakah rintangan berada lebih jauh di jalan
if blockedWaypointIndex >= nextWaypointIndex then
-- Hentikan pendeteksi blok jalur sampai jalur dihitung ulang
blockedConnection:Disconnect()
-- Fungsi panggil untuk menghitung ulang jalur baru
followPath(destination)
end
end)
-- Deteksi ketika gerakan ke waypoint berikutnya selesai
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Tingkatkan indeks waypoint dan pindah ke waypoint berikutnya
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Pada awalnya pindah ke titik jalur kedua (titik jalur pertama adalah mulaijalur; lewati)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
Tangani jalur diblokir
Banyak dunia Roblox dinamis; bagian mungkin bergerak atau jatuh dan lantai mungkin runtuh.Ini dapat memblokir jalur yang dihitung dan mencegah karakter mencapai tujuan.Untuk menangani ini, Anda dapat menghubungkan acara Path.Blocked dan menghitung ulang jalur di sekitar apa pun yang diblokirnya.
Skrip Lokal - Pencarian Karakter
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)
-- Hitung jalur
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalur cara
waypoints = path:GetWaypoints()
-- Deteksi apakah jalur menjadi diblokir
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Periksa apakah rintangan berada lebih jauh di jalan
if blockedWaypointIndex >= nextWaypointIndex then
-- Hentikan pendeteksi blok jalur sampai jalur dihitung ulang
blockedConnection:Disconnect()
-- Fungsi panggil untuk menghitung ulang jalur baru
followPath(destination)
end
end)
end
end
Pengubah penemuan jalur
Secara default, Path:ComputeAsync() kembali jalur paling pendek antara titik awal dan tujuan, dengan pengecualian bahwa ia berusaha menghindari lompatan.Ini terlihat tidak alami dalam beberapa situasi - kejadian, jalur mungkin melewati air daripada di atas jembatan terdekat hanya karena jalur melalui air lebih pendek secara geometris.

Untuk meningkatkan pencarian jalur lebih jauh, Anda dapat menerapkan modifikasi pencarian jalur untuk menghitung jalur yang lebih pintar melintasi berbagai materi , di sekitar wilayah yang didefinisikan , atau melalui hambatan.
Tetapkan biaya material
Saat bekerja dengan Terrain dan BasePart materi, Anda dapat menyertakan tabel Costs dalam CreatePath() untuk membuat materi tertentu lebih dapat dilalui daripada yang lain.Semua bahan memiliki biaya default 1 dan bahan apa pun dapat didefinisikan sebagai tidak dapat dilalui dengan menetapkan nilainya menjadi math.huge .
Kunci di tabel Costs harus menjadi nama string yang mewakili nama Enum.Material , misalnya Water untuk Enum.Material.Water .
Skrip Lokal - Pencarian Karakter
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}})
Bekerja dengan wilayah
Dalam beberapa kasus, preferensi bahan tidak cukup.Sebagai contoh, Anda mungkin ingin karakter menghindari wilayah yang didefinisikan , terlepas dari bahan di bawah kaki.Ini dapat dicapai dengan menambahkan objek PathfindingModifier ke bagian.
Buat bagian Anchored sekitar wilayah berbahaya dan atur propertinya CanCollide ke palsu .
Sisipkan instansi PathfindingModifier ke bagian, temukan propertinya Label , dan atribusikan nama yang berarti seperti DangerZone .
Sertakan tabel Costs dalam CreatePath() yang berisi kunci cocok dan nilai numerik terkait.Seorang modifikator dapat didefinisikan sebagai tidak dapat dilalui dengan menetapkan nilainya ke math.huge .
Skrip Lokal - Pencarian Karakterlocal 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}})
Abaikan hambatan
Dalam beberapa kasus, berguna untuk menemukan jalan melalui hambatan padat seolah-olah mereka tidak ada.Ini memungkinkan Anda menghitung jalur melalui penghalang fisik tertentu, versus komputasi gagal sepenuhnya.
Buat bagian Anchored sekitar objek dan atur propertinya CanCollide ke palsu .
Sisipkan instansi PathfindingModifier ke bagian dan aktifkan propertinya PassThrough.
Sekarang, ketika jalur dihitung dari NPC zombie ke karakter pemain, jalur meluas melewati pintu dan Anda dapat meminta zombie untuk melintasinya.Bahkan jika zombie tidak dapat membuka pintu, ia bereaksi seolah-olah "mendengar" karakter di balik pintu.
Tautan penemuan jalur
Terkadang perlu menemukan jalur melintasi ruang yang tidak dapat dilewati secara normal, seperti melintasi jurang, dan melakukan tindakan khusus untuk mencapai waypoint berikutnya.Ini dapat dicapai melalui objek PathfindingLink.
Menggunakan contoh pulau dari atas, Anda dapat membuat agen menggunakan perahu alih-alih berjalan melintasi semua jembatan.

Untuk membuat PathfindingLink menggunakan contoh ini:
Untuk membantu dengan visualisasi dan debugging, beralih pada Tautan Pencarian Jalur dari widget Opsi Visualisasi di sudut kanan atas tampilan 3D.
Buat dua Attachments , satu di kursi kapal dan satu di dekat titik pendaratan kapal.
Buat objek PathfindingLink di ruang kerja, lalu atribusikan properti Attachment0 dan Attachment1 ke lampiran awal dan akhir masing-masing.
Tetukan nama yang berarti seperti Gunakan Kapal pada properti Label.Nama ini digunakan sebagai bendera dalam skrip penemuan jalur untuk memicu tindakan khusus saat agen mencapai titik tautan awal.
Sertakan tabel Costs dalam CreatePath() yang berisi kunci Water dan kunci khusus yang cocok dengan nama properti Label.Atribusikan kunci khusus nilai yang lebih rendah dari Water .
Skrip Lokal - Pencarian Karakterlocal 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}})Dalam peristiwa yang menembak ketika waypoint tercapai, tambahkan pemeriksaan khusus untuk nama modifikasi Label dan ambil tindakan berbeda dari Humanoid:MoveTo() - dalam kasus ini, memanggil fungsi untuk menempatkan agen di perahu, memindahkan perahu melintasi air, dan melanjutkan jalur agen saat tiba di pulau tujuan.
Skrip Lokal - Pencarian Karakterlocal PathfindingService = game:GetService("PathfindingService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")local Workspace = game:GetService("Workspace")local path = PathfindingService:CreatePath({Costs = {Water = 20,UseBoat = 1}})local player = Players.LocalPlayerlocal character = player.Characterlocal humanoid = character:WaitForChild("Humanoid")local TEST_DESTINATION = Vector3.new(228.9, 17.8, 292.5)local waypointslocal nextWaypointIndexlocal reachedConnectionlocal blockedConnectionlocal function followPath(destination)-- Hitung jalurlocal success, errorMessage = pcall(function()path:ComputeAsync(character.PrimaryPart.Position, destination)end)if success and path.Status == Enum.PathStatus.Success then-- Dapatkan titik jalur carawaypoints = path:GetWaypoints()-- Deteksi apakah jalur menjadi diblokirblockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)-- Periksa apakah rintangan berada lebih jauh di jalanif blockedWaypointIndex >= nextWaypointIndex then-- Hentikan pendeteksi blok jalur sampai jalur dihitung ulangblockedConnection:Disconnect()-- Fungsi panggil untuk menghitung ulang jalur barufollowPath(destination)endend)-- Deteksi ketika gerakan ke waypoint berikutnya selesaiif not reachedConnection thenreachedConnection = humanoid.MoveToFinished:Connect(function(reached)if reached and nextWaypointIndex < #waypoints then-- Tingkatkan indeks waypoint dan pindah ke waypoint berikutnyanextWaypointIndex += 1-- Gunakan kapal jika label waypoint adalah "UseBoat"; jika tidak, pindah ke waypoint berikutnyaif waypoints[nextWaypointIndex].Label == "UseBoat" thenuseBoat()elsehumanoid:MoveTo(waypoints[nextWaypointIndex].Position)endelsereachedConnection:Disconnect()blockedConnection:Disconnect()endend)end-- Pada awalnya pindah ke titik jalur kedua (titik jalur pertama adalah mulaijalur; lewati)nextWaypointIndex = 2humanoid:MoveTo(waypoints[nextWaypointIndex].Position)elsewarn("Path not computed!", errorMessage)endendfunction useBoat()local boat = Workspace.BoatModelhumanoid.Seated:Connect(function()-- Mulai gerakkan kapal jika agen dudukif humanoid.Sit thentask.wait(1)boat.CylindricalConstraint.Velocity = 5end-- Deteksi posisi batasan dalam kaitannya dengan pulaulocal boatPositionConnectionboatPositionConnection = RunService.PostSimulation:Connect(function()-- Hentikan kapal saat berdekatan dengan pulauif boat.CylindricalConstraint.CurrentPosition >= 94 thenboatPositionConnection:Disconnect()boat.CylindricalConstraint.Velocity = 0task.wait(1)-- Hapus agen dan lanjutkan ke tujuanhumanoid.Sit = falsehumanoid:MoveTo(waypoints[nextWaypointIndex].Position)endend)end)endfollowPath(TEST_DESTINATION)
Kompatibilitas streaming
Pengalaman dalam streaming instansi adalah fitur kuat yang memuat dan melepaskan konten 3D secara dinamis saat karakter pemain bergerak di seluruh dunia.Saat mereka menjelajahi ruang 3D, subset baru dari aliran ruang ke perangkat mereka dan beberapa subset yang ada mungkin akan diputar keluar.
Pertimbangkan praktik terbaik berikut untuk menggunakan PathfindingService dalam pengalaman yang diaktifkan streaming:
Streaming dapat memblokir atau membuka jalur tertentu saat karakter bergerak di sepanjangnya.Sebagai contoh, saat karakter berlari melalui hutan, pohon mungkin mengalir di suatu tempat di depan mereka dan menghalangi jalan.Untuk membuat pekerjaan penemuan jalur berjalan lancar dengan streaming, sangat disarankan agar Anda menggunakan teknik penanganan jalur diblokir dan menghitung ulang jalur saat diperlukan.
Pendekatan umum dalam penemuan jalur adalah menggunakan koordinat objek yang ada untuk komputasi , seperti menetapkan tujuan jalur ke posisi model Peti Harta Karun yang ada di dunia.Pendekatan ini sepenuhnya kompatibel dengan sisi server Scripts karena server memiliki pandangan lengkap tentang dunia setiap saat, tetapi LocalScripts dan ModuleScripts yang dijalankan di klien mungkin gagal jika mereka mencoba untuk menghitung jalur ke objek yang tidak diputar di dalamnya.
Untuk mengatasi masalah ini, pertimbangkan untuk mengatur tujuan ke posisi BasePart dalam model abadi.Model permanen dimuat segera setelah pemain bergabung dan mereka tidak pernah streaming keluar, jadi skrip sisi klien dapat terhubung ke peristiwa PersistentLoaded dan mengakses model dengan aman untuk membuat waypoint setelah peristiwa terjadi.