Pathfinding adalah proses pemindahan karakter di sepanjang jalan logikal untuk mencapai tujuan, menghindari rintangan dan (opsional) bahan berbahaya atau wilayah yang ditentukan.
Visualisasi Navigasi
Untuk membantu dengan pemetauan jalan dan debug, Studio dapat menyajikan jaringan navigasi dan label modifier. Untuk mengaktifkannya, aktifkan Jaringan navigasi dan Pathfinding modifier dari widget 2>Opsi Penglihatan2> di sudut atas kanan 3D viewport.
Dengan Mesh navigasi diaktifkan, area berwarna menunjukkan di mana karakter mungkin berjalan atau berenang, sementara area non-berwarna diblokir. Panah kecil menunjukkan area yang akan dicoba karakter dengan melompat, mengasumsi Anda menetapkan AgentCanJump untuk true ketika membuat jalan.
Dengan Pathfinding modifier) yang aktif, label teks menunjukkan bahan dan wilayah tertentu yang dipertimbangkan saat menggunakan Pathfinding modifier .
Keterbatasan yang Dikenal
Fitur Pathfinding khusus membatasi untuk menjamin pemrosesan yang efisien dan pelaksanaanyang optimal.
Batas Penempatan Vertikal
Pencarian jalan hanya mempertimbangkan bagian dalam batas vertikal tertentu:
- Lebih Rendah — Bagian dengan koordinat bawah Y kurang dari -65,536 studs diabaikan.
- Atas Boundary — Bagian dengan koordinat Y teratas mengesatkan 65.536 studs diabaikan.
- Jarak vertikal dari bagian bawah terendah Y koordinasi ke atas bagian teratas Y koordinasi tidak boleh melebihi 65.536 stud; jika tidak, sistem pemetaan jalan akan mengabaikan bagian-bagian ini selama perhitungan pemetaan jalan.
Membatasi Jarak Pencarian
Jarak langsung antara garis pandangan sejak awal hingga titik akhir harus tidak melebihi 3.000 stud. Melebihi jarak ini akan menghasilkan status NoPath.
Membuat Jalan
Pathfinding dimulai melalui PathfindingService dan fungsinya CreatePath().
Skrip Lokal
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath()
CreatePath() menerima tabel parameter opcional yang menyempurnakan cara karakter (agens) bergerak di jalan.
Kunci | Deskripsi | Jenis | Standar |
---|---|---|---|
AgentRadius | Radius agen, dalam stud. Berguna untuk menentukan minimum separasi dari rintangan. | float | 2 |
AgentHeight | Tinggi agen, dalam studs. Ruang kosong yang lebih kecil dari nilai ini, seperti ruang di bawah tangga, akan ditandai sebagai tidak dapat dilewati. | float | 5 |
AgentCanJump | Menentukan apakah melompat selama pemetaan jalan diizinkan. | boolean | true |
AgentCanClimb | Menentukan apakah TrussParts dapat diizinkan selama pemetaan jalan. | boolean | false |
WaypointSpacing | Menempatkan antara titik jalan tengah dalam jalan. Jika diatur ke math.huge , tidak akan ada titik jalan tengah. | nomor | 4 |
Costs | Tabel bahan atau di definisi PathfindingModifiers dan biaya untuk melintasi. Berguna untuk membuat agen menyukai beberapa bahan/wilayah tertentu daripada yang lain. Lihat modifier untuk rincian. | tabel | nil |
Skrip Lokal
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath({AgentRadius = 3,AgentHeight = 6,AgentCanJump = false,Costs = {Water = 20}})
Catat bahwa agen dapat menaiki TrussParts selama pathfinding jika Anda menetapkan AgentCanClimb ke true ketika 1> membuat jalan1> dan tidak ada yang menghentikan
Skrip Lokal - JalurPemasangan Truss
local PathfindingService = game:GetService("PathfindingService")local path = PathfindingService:CreatePath({AgentCanClimb = true,Costs = {Climb = 2 -- Biaya jalan per登山; default adalah 1}})
Pindah Sekaligus
Bagian ini menggunakan script pemetaan jalan berikut untuk karakter pemain. Untuk menguji saat membaca:
- Salinan kode ke dalam LocalScript dalam StarterCharacterScripts .
- Edit line 11 to a Vector3 destination that the player character can reach.
- Lewati bagian berikut untuk mempelajari tentang perhitungan jalan dan gerakan karakter.
Skrip Lokal - Pemetaan Karakter
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)
-- Hitung jalan
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalan masuk
waypoints = path:GetWaypoints()
-- Deteksi jika jalan menjadi diblokir
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Periksa apakah rintangan berada lebih bawah jalan
if blockedWaypointIndex >= nextWaypointIndex then
-- Berhenti mendeteksi blok jalan sampai jalan dihitung ulang
blockedConnection:Disconnect()
-- Panggil fungsi untuk menghitung ulang jalan baru
followPath(destination)
end
end)
-- Deteksi saat gerakan ke titik pemotongan berikutnya selesai
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Tingkatkan indeks poin jalan dan pindah ke poin jalan berikutnya
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Pindah ke titik balik (pertama titik balik adalah titik mulai; lompat)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)
Menghitung Jalur
Setelah Anda telah menciptakan jalan yang valid dengan CreatePath() , itu harus dihitung dengan memanggil Path:ComputeAsync() dengan 11> Datatype.Vector3 untuk kedua titik awal dan tujuan.
Skrip Lokal - Pemetaan Karakter
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)
-- Hitung jalan
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
end
Mendapatkan Waypoints
Setelah Path dihitung, itu akan berisi serangkaian poin jalan setapak yang melacak jalan dari awal hingga akhiri. Titik-titik ini dapat dikumpulkan dengan fungsi Path:GetWaypoints().
Skrip Lokal - Pemetaan Karakter
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)
-- Hitung jalan
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalan masuk
waypoints = path:GetWaypoints()
end
end
Pemindahan Jalan
Setiap waypoint terdiri dari kedua posisi ( Vector3 ) dan tindakan ( 2> Class.Humanoid:MoveTo
Skrip Lokal - Pemetaan Karakter
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)
-- Hitung jalan
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalan masuk
waypoints = path:GetWaypoints()
-- Deteksi jika jalan menjadi diblokir
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Periksa apakah rintangan berada lebih bawah jalan
if blockedWaypointIndex >= nextWaypointIndex then
-- Berhenti mendeteksi blok jalan sampai jalan dihitung ulang
blockedConnection:Disconnect()
-- Panggil fungsi untuk menghitung ulang jalan baru
followPath(destination)
end
end)
-- Deteksi saat gerakan ke titik pemotongan berikutnya selesai
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Tingkatkan indeks poin jalan dan pindah ke poin jalan berikutnya
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Pindah ke titik balik (pertama titik balik adalah titik mulai; lompat)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
Menangani Jalan yang Diblokir
Banyak dunia Roblox dinamis; bagian mungkin bergerak atau jatuh dan lantai mungkin runtuh. Ini dapat menghalangi jalan yang dihitung dan mencegah karakter mencapai tujuan tujuan. Untuk menangani ini, Anda dapat menghubungkan acara Path.Blocked dan menghitung jalan di sekitar apa pun yang diblokir.
Skrip Lokal - Pemetaan Karakter
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)
-- Hitung jalan
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Dapatkan titik jalan masuk
waypoints = path:GetWaypoints()
-- Deteksi jika jalan menjadi diblokir
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Periksa apakah rintangan berada lebih bawah jalan
if blockedWaypointIndex >= nextWaypointIndex then
-- Berhenti mendeteksi blok jalan sampai jalan dihitung ulang
blockedConnection:Disconnect()
-- Panggil fungsi untuk menghitung ulang jalan baru
followPath(destination)
end
end)
end
end
Modifikasi Pencarian Jalan
Secara default, Path:ComputeAsync() mengembalikan jalan pendekest antara titik awal dan tujuan, dengan pengecualian bahwa ia mencoba untuk menghindari lompatan. Ini terlihat tidak alami dalam beberapa situasi - kejadian, jalan melalui air mungkin pergi melalui air hanya karena jalan melalui air lebih geometrikally pendek.
Untuk mengoptimalkan pencarian jalan lebih jauh, Anda dapat menerapkan modifikator pencarian untuk menghitung jalan yang lebih pintar di berbagai 材料 , di sekitar wilayah , atau melalui 2>halang rintang2> .
Mengatur Biaya Material
Ketika bekerja dengan Terrain dan BasePart materi, Anda dapat mencakup tabel Costs di dalam 1> Class.PathfindingService:CreatePath()|CreatePath()1> untuk membuat
Kunci dalam tabel Costs harus menjadi nama string mewakili nama Enum.Material, misalnya Water untuk 1> En册.Material.Water1> .
Skrip Lokal - Pemetaan Karakter
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}})
Bekerja Dengan Wilayah
Dalam beberapa kasus, preferensi bahan tidak cukup. Misalnya, Anda mungkin ingin karakter menghindari wilayah yang ditentukan , terlepas dari bahan di bawah kaki. Ini dapat dicapai dengan menambahkan objek PathfindingModifier ke bagian.
Buat bagian Anchored di sekitar wilayah berbahaya dan tetapkan propperti CanCollide nya ke false .
Sisipkan instansi PathfindingModifier ke bagian, temukan prop性 Label , dan atribusikan nama yang berarti seperti DangerZone .
Masukkan tabel Costs dalam CreatePath() yang berisi kunci yang cocok dan nilai numerik yang terkait. Modifier dapat di definisikan sebagai tidak dapat dilintasi dengan menetapkan nilainya menjadi math.huge .
Skrip Lokal - Pemetaan Karakterlocal PathfindingService = game:GetService("PathfindingService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")local path = PathfindingService:CreatePath({Costs = {DangerZone = math.huge}})
Mengabaikan Rintangan
Dalam beberapa kasus, penting untuk menempuh jalan melalui rintangan padat seolah-olah mereka tidak ada. Ini memungkinkan Anda untuk menghitung jalan melalui blok fisik spesifik, bukan kesalahan perhitungan.
Buat bagian Anchored di sekitar objek dan tetapkan propietas CanCollide nya ke false .
Sisipkan instansi PathfindingModifier ke bagian dan aktifkan propertinya PassThrough.
Sekarang, ketika jalan dibuat dari NPC zombie ke karakter pemain, jalan itu menyebar di luar pintu dan Anda dapat meminta zombie untuk menyeberanginya. Bahkan jika zombie tidak dapat membuka pintu, reaksinya seolah-olah "mendengar" karakter di belakang pintu.
Pathfinding Links
Terkadang diperlukan untuk menemukan jalan melintasi ruang yang tidak dapat dilewati secara normal, seperti melintasi terowongan, dan melakukan tindakan khusus untuk mencapai titik jalan berikutnya. Ini dapat dicapai melalui objek PathfindingLink.
Menggunakan contoh pulau di atas, Anda dapat membuat agen menggunakan perahu alih-alih berjalan melintasi semua jembatan.
Untuk membuat PathfindingLink menggunakan contoh ini:
Untuk membantu dengan visualisasi dan debug, toggle on Pathfinding links dari widget Opsi Visualisasi di sudut atas kanan 3D viewport.
Buat dua Attachments , satu di kursi kapal dan satu di dekat titik landas kapal.
Buat objek PathfindingLink di ruang kerja, lalu atribusikan Attachment0 dan Attachment1 ke properti 1> Tempat01> dan 4> Tempat1 4> secara masing-masing.
Tetapkan nama yang berarti seperti GunakanKapal ke properti Label nya. Nama ini digunakan sebagai bendera dalam script pathfinding untuk menetapkan tindakan khusus saat agen mencapai titik awal link.
Masukkan tabel Costs di dalam CreatePath() yang berisi kunci Water dan kunci khusus yang cocok dengan nama propinsi 1> Class.PathfindingLink.Label|Label1> . Atur kunci khusus ke nilai yang lebih rendah dari 4> Water4> .
Skrip Lokal - Pemetaan Karakterlocal PathfindingService = game:GetService("PathfindingService")local Players = game:GetService("Players")local RunService = game:GetService("RunService")local path = PathfindingService:CreatePath({Costs = {Water = 20,UseBoat = 1}})Dalam acara yang menyetel saat sebuah waypoint dicapai, tambahkan check khusus untuk nama modifier Label dan ambil tindakan yang berbeda daripada Humanoid:MoveTo() — dalam kasus ini, memanggil fungsi untuk duduk agen di kapal, menyebarkan kapal melintasi air, dan melanjut
Skrip Lokal - Pemetaan Karakterlocal 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.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 jalanlocal success, errorMessage = pcall(function()path:ComputeAsync(character.PrimaryPart.Position, destination)end)if success and path.Status == Enum.PathStatus.Success then-- Dapatkan titik jalan masukwaypoints = path:GetWaypoints()-- Deteksi jika jalan menjadi diblokirblockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)-- Periksa apakah rintangan berada lebih bawah jalanif blockedWaypointIndex >= nextWaypointIndex then-- Berhenti mendeteksi blok jalan sampai jalan dihitung ulangblockedConnection:Disconnect()-- Panggil fungsi untuk menghitung ulang jalan barufollowPath(destination)endend)-- Deteksi saat gerakan ke titik pemotongan berikutnya selesaiif not reachedConnection thenreachedConnection = humanoid.MoveToFinished:Connect(function(reached)if reached and nextWaypointIndex < #waypoints then-- Tingkatkan indeks poin jalan dan pindah ke poin jalan berikutnyanextWaypointIndex += 1-- Gunakan kapal jika label jalan masuk adalah "Gunakan Kapal"; jika tidak, pindah ke jalan masuk berikutnyaif waypoints[nextWaypointIndex].Label == "UseBoat" thenuseBoat()elsehumanoid:MoveTo(waypoints[nextWaypointIndex].Position)endelsereachedConnection:Disconnect()blockedConnection:Disconnect()endend)end-- Pindah ke titik balik (pertama titik balik adalah titik mulai; lompat)nextWaypointIndex = 2humanoid:MoveTo(waypoints[nextWaypointIndex].Position)elsewarn("Path not computed!", errorMessage)endendfunction useBoat()local boat = workspace.BoatModelhumanoid.Seated:Connect(function()-- Mulai kapal bergerak jika agen dudukif humanoid.Sit thentask.wait(1)boat.CylindricalConstraint.Velocity = 5end-- Mendeteksi posisi batasan dalam hubungannya dengan pulaulocal boatPositionConnectionboatPositionConnection = RunService.PostSimulation:Connect(function()-- Berhentikan kapal saat berada di dekat pulauif boat.CylindricalConstraint.CurrentPosition >= 94 thenboatPositionConnection:Disconnect()boat.CylindricalConstraint.Velocity = 0task.wait(1)-- Batalkan agen dan lanjutkan ke tujuanhumanoid.Sit = falsehumanoid:MoveTo(waypoints[nextWaypointIndex].Position)endend)end)endfollowPath(TEST_DESTINATION)
Kesesuaian Pengirim
In-experience streaming instance adalah fitur kuat yang secara dinamis memuat dan menghapus 3D konten sebagai karakter pemain bergerak di sekitar dunia. Saat mereka menjelajahi ruang 3D, beberapa subset dari ruang stream ke perangkat mereka dan beberapa subset lainnya mungkin ber流出.
Pertimbangkan praktik terbaik berikut untuk menggunakan PathfindingService dalam pengalaman yang mendukung streaming:
Menghosting dapat menyetel atau menghapus jalan yang diberikan sebagai karakter bergerak di sepanjang jalan. Misalnya, saat karakter berlari melalui hutan, pohon mungkin menyetel di suatu tempat di depan mereka dan mengganggu jalan. Untuk membuat menemukan jalan bekerja tanpa masalah dengan menyetel, sangat direkomendasikan untuk menggunakan teknik Menangani Blok
Pendekatan umum dalam pemetaan jalan adalah menggunakan koordinat dari objek yang ada untuk menghitung, seperti menetapkan tujuan jalan ke posisi dari model Peti Hart
Untuk mengatasi masalah ini, pertimbangkan untuk menetapkan tujuan ke lokasi Class.BasePart dalam model BasePart yang bertahan. Model bertahan akan dimuat segera setelah pemain bergabung dan mereka tidak pernah menyelip, jadi skrip sisi klien dapat terhubung ke acara Class.Workspace.PersistentLoaded dan d