Pencarian karakter

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

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.

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

Navigation mesh showing in Studio

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

Navigation labels showing on navigation mesh

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.

KunciDeskripsiJenisStandar
AgentRadiusRadius agen, dalam stud. Berguna untuk menentukan jarak minimum dari penghalang.integer2
AgentHeightTinggi agen, dalam stud. Ruang kosong yang lebih kecil dari nilai ini, seperti ruang di bawah tangga, akan ditandai sebagai tidak dapat dilalui.integer5
AgentCanJumpMenentukan apakah melompat selama pencarian jalur diizinkan.booleantrue
AgentCanClimbMenentukan apakah pendakian TrussParts selama pencarian jalur diizinkan.booleanfalse
WaypointSpacingJarak antara titik jalan tengah di jalur. Jika diatur ke math.huge, tidak akan ada titik jalan tengah.angka4
CostsTabel materi atau didefinisikan PathfindingModifiers dan biaya untuk melintasi.Berguna untuk membuat agen lebih memilih materi/wilayah tertentu daripada yang lain.Lihat modifikator untuk rincian.mejanil
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.

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

  1. Salin kode ke dalam LocalScript dalam StarterCharacterScripts .
  2. Tetapkan variabel TEST_DESTINATION untuk tujuan Vector3 di dunia 3D Anda yang dapat dicapai karakter pemain.
  3. 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
Path start/end marked on series of islands and bridges

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
Waypoints indicated across computed path
Titik jalan yang ditunjukkan di sepanjang jalur yang dihitung

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.

Two paths indicated with the shorter path not necessarily more logical

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.

  1. Buat bagian Anchored sekitar wilayah berbahaya dan atur propertinya CanCollide ke palsu .

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

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

  1. Buat bagian Anchored sekitar objek dan atur propertinya CanCollide ke palsu .

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

    Zombie NPC path passing through the previously blocking door

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.

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 debugging, beralih pada Tautan Pencarian Jalur dari widget Opsi Visualisasi di sudut kanan atas tampilan 3D.

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

    Attachments created for pathfinding link's start and end
  3. Buat objek PathfindingLink di ruang kerja, lalu atribusikan properti Attachment0 dan Attachment1 ke lampiran awal dan akhir masing-masing.

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

    Label property specified for PathfindingLink
  5. 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 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,
    UseBoat = 1
    }
    })
  6. 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 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,
    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 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
    -- Gunakan kapal jika label waypoint adalah "UseBoat"; jika tidak, pindah ke waypoint berikutnya
    if waypoints[nextWaypointIndex].Label == "UseBoat" then
    useBoat()
    else
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    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
    function useBoat()
    local boat = Workspace.BoatModel
    humanoid.Seated:Connect(function()
    -- Mulai gerakkan kapal jika agen duduk
    if humanoid.Sit then
    task.wait(1)
    boat.CylindricalConstraint.Velocity = 5
    end
    -- Deteksi posisi batasan dalam kaitannya dengan pulau
    local boatPositionConnection
    boatPositionConnection = RunService.PostSimulation:Connect(function()
    -- Hentikan kapal saat berdekatan dengan pulau
    if boat.CylindricalConstraint.CurrentPosition >= 94 then
    boatPositionConnection:Disconnect()
    boat.CylindricalConstraint.Velocity = 0
    task.wait(1)
    -- Hapus agen dan lanjutkan ke tujuan
    humanoid.Sit = false
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    end)
    end)
    end
    followPath(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.