Pemetaan Karakter

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

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.

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

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.

Navigation mesh showing in Studio

Dengan Pathfinding modifier) yang aktif, label teks menunjukkan bahan dan wilayah tertentu yang dipertimbangkan saat menggunakan Pathfinding modifier .

Navigation labels showing on navigation mesh

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.

KunciDeskripsiJenisStandar
AgentRadiusRadius agen, dalam stud. Berguna untuk menentukan minimum separasi dari rintangan.float2
AgentHeightTinggi agen, dalam studs. Ruang kosong yang lebih kecil dari nilai ini, seperti ruang di bawah tangga, akan ditandai sebagai tidak dapat dilewati.float5
AgentCanJumpMenentukan apakah melompat selama pemetaan jalan diizinkan.booleantrue
AgentCanClimbMenentukan apakah TrussParts dapat diizinkan selama pemetaan jalan.booleanfalse
WaypointSpacingMenempatkan antara titik jalan tengah dalam jalan. Jika diatur ke math.huge , tidak akan ada titik jalan tengah.nomor4
CostsTabel 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.tabelnil
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

Path going up a climbable TrussPart ladder
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:

  1. Salinan kode ke dalam LocalScript dalam StarterCharacterScripts .
  2. Edit line 11 to a Vector3 destination that the player character can reach.
  3. 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
Path start/end marked on series of islands and bridges

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
Waypoints indicated across computed path
Poin jalan yang ditunjukkan melalui jalan yang dihitung

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.

Two paths indicated with the shorter path not necessarily more logical

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.

  1. Buat bagian Anchored di sekitar wilayah berbahaya dan tetapkan propperti CanCollide nya ke false .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Sisipkan instansi PathfindingModifier ke bagian, temukan prop性 Label , dan atribusikan nama yang berarti seperti DangerZone .

    PathfindingModifier instance with Label property set to DangerZone
  3. 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 Karakter

    local 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.

  1. Buat bagian Anchored di sekitar objek dan tetapkan propietas CanCollide nya ke false .

    Anchored part defining a region to apply a pathfinding modifier to
  2. Sisipkan instansi PathfindingModifier ke bagian dan aktifkan propertinya PassThrough.

    PathfindingModifier instance with PassThrough property enabled

    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.

    Zombie NPC path passing through the previously blocking door

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.

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

Untuk membuat PathfindingLink menggunakan contoh ini:

  1. Untuk membantu dengan visualisasi dan debug, toggle on Pathfinding links dari widget Opsi Visualisasi di sudut atas kanan 3D viewport.

  2. Buat dua Attachments , satu di kursi kapal dan satu di dekat titik landas kapal.

    Attachments created for pathfinding link's start and end
  3. Buat objek PathfindingLink di ruang kerja, lalu atribusikan Attachment0 dan Attachment1 ke properti 1> Tempat01> dan 4> Tempat1 4> secara masing-masing.

    Attachment0/Attachment1 properties of a PathfindingLink PathfindingLink visualized in the 3D world
  4. 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.

    Label property specified for PathfindingLink
  5. 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 Karakter

    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. 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 Karakter

    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)
    -- 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
    -- Gunakan kapal jika label jalan masuk adalah "Gunakan Kapal"; jika tidak, pindah ke jalan masuk berikutnya
    if waypoints[nextWaypointIndex].Label == "UseBoat" then
    useBoat()
    else
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    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
    function useBoat()
    local boat = workspace.BoatModel
    humanoid.Seated:Connect(function()
    -- Mulai kapal bergerak jika agen duduk
    if humanoid.Sit then
    task.wait(1)
    boat.CylindricalConstraint.Velocity = 5
    end
    -- Mendeteksi posisi batasan dalam hubungannya dengan pulau
    local boatPositionConnection
    boatPositionConnection = RunService.PostSimulation:Connect(function()
    -- Berhentikan kapal saat berada di dekat pulau
    if boat.CylindricalConstraint.CurrentPosition >= 94 then
    boatPositionConnection:Disconnect()
    boat.CylindricalConstraint.Velocity = 0
    task.wait(1)
    -- Batalkan agen dan lanjutkan ke tujuan
    humanoid.Sit = false
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    end)
    end)
    end
    followPath(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