Sebuah tabrakan terjadi ketika dua objek 3D bersentuhan di dalam dunia 3D. Untuk penanganan tabrakan yang disesuaikan, BasePart memiliki serangkaian peristiwa tabrakan dan teknik penyaringan tabrakan, sehingga Anda dapat mengontrol objek fisik mana yang bertabrakan dengan yang lain.
Peristiwa tabrakan
Peristiwa tabrakan terjadi ketika dua BaseParts bersentuhan atau berhenti bersentuhan di dunia 3D. Anda dapat mendeteksi tabrakan ini melalui peristiwa Touched dan TouchEnded yang terjadi terlepas dari nilai properti CanCollide dari masing-masing bagian. Saat mempertimbangkan penanganan tabrakan pada bagian, perhatikan hal berikut:
- Properti CanTouch dari sebuah bagian menentukan apakah itu memicu peristiwa tabrakan. Jika diatur ke false, baik Touched maupun TouchEnded tidak akan dipicu.
- Properti CanCollide dari sebuah bagian mempengaruhi apakah itu akan secara fisik bertabrakan dengan bagian lain dan menyebabkan gaya bekerja pada mereka. Bahkan jika CanCollide dinonaktifkan untuk sebuah bagian, Anda dapat mendeteksi sentuhan dan tidak-sentuhan melalui peristiwa Touched dan TouchEnded.
- Peristiwa Touched dan TouchEnded hanya dipicu sebagai hasil dari gerakan fisik, bukan dari perubahan Position atau CFrame yang menyebabkan sebuah bagian berinteraksi atau berhenti berinteraksi dengan bagian lain.
Touched
Peristiwa Touched dipicu ketika sebuah BasePart bersentuhan dengan yang lain, atau dengan voxel Terrain. Ini hanya dipicu sebagai hasil dari simulasi fisik dan tidak akan dipicu ketika Position atau CFrame bagian diatur secara eksplisit sehingga berinteraksi dengan bagian atau voxel lain.
Pola kode berikut menunjukkan bagaimana peristiwa Touched dapat dihubungkan ke fungsi kustom onTouched(). Perhatikan bahwa peristiwa ini mengirim argumen otherPart ke fungsi, menunjukkan bagian lain yang terlibat dalam tabrakan.
local part = workspace.Part
local function onTouched(otherPart)
print(part.Name .. " bertabrakan dengan " .. otherPart.Name)
end
part.Touched:Connect(onTouched)Perhatikan bahwa peristiwa Touched dapat dipicu beberapa kali dalam waktu singkat berdasarkan tabrakan fisik yang halus, seperti ketika objek bergerak "menetap" ke posisi istirahat atau ketika tabrakan melibatkan model multi-bagian. Untuk menghindari pemicu lebih banyak peristiwa Touched daripada yang diperlukan, Anda dapat menerapkan sistem debounce sederhana yang memberlakukan periode "cooldown" melalui sebuah atribut.
local part = workspace.Part
local COOLDOWN_TIME = 1
local function onTouched(otherPart)
if not part:GetAttribute("Touched") then
print(part.Name .. " bertabrakan dengan " .. otherPart.Name)
part:SetAttribute("Touched", true) -- Atur atribut ke true
task.wait(COOLDOWN_TIME) -- Tunggu durasi cooldown
part:SetAttribute("Touched", false) -- Reset atribut
end
end
part.Touched:Connect(onTouched)TouchEnded
Peristiwa TouchEnded dipicu ketika seluruh batas tabrakan dari sebuah BasePart keluar dari batas BasePart lain atau voxel Terrain yang terisi. Ini hanya dipicu sebagai hasil dari simulasi fisik dan tidak akan dipicu ketika Position atau CFrame bagian diatur secara eksplisit sehingga berhenti berinteraksi dengan bagian atau voxel lain.
Pola kode berikut menunjukkan bagaimana peristiwa TouchEnded dapat dihubungkan ke fungsi kustom onTouchEnded(). Seperti Touched, peristiwa ini mengirim argumen otherPart ke fungsi, menunjukkan bagian lain yang terlibat.
local part = workspace.Part
local function onTouchEnded(otherPart)
print(part.Name .. " tidak lagi bersentuhan dengan " .. otherPart.Name)
end
part.TouchEnded:Connect(onTouchEnded)Ringkasan tabrakan
Touched memberi tahu Anda bahwa sebuah tabrakan terjadi, tetapi tidak di mana itu terjadi, dari arah mana itu datang, atau seberapa keras itu. Untuk data kontak yang lebih rinci dari mesin fisika, panggil BindToCollisionSummaries() pada sebuah bagian. Ini mengambil sebuah callback dan mengembalikan RBXScriptConnection yang dapat Anda putuskan ketika Anda tidak lagi memerlukan data tersebut. Ini adalah API terpisah dari Touched, jadi jangan panggil dari dalam handler Touched.
Callback dijalankan sekali per frame, setelah langkah fisika selesai. Ini menerima sebuah tabel dengan ringkasan setiap tabrakan yang terlibat dalam bagian selama frame tersebut. Setiap ringkasan menggambarkan satu area kontak antara bagian yang disubscribe dan bagian lain. Ringkasan dibekukan dan tidak dapat diubah. Masing-masing memiliki bidang berikut:
| Bidang | Tipe | Deskripsi |
|---|---|---|
| Time | number | Waktu simulasi dari substep. |
| Part0 | BasePart | Bagian yang disubscribe. |
| Part1 | BasePart | Bagian lain dalam pasangan. |
| Point | Vector3 | Titik kontak rata-rata, dalam ruang dunia. |
| Normal | Vector3 | Normal unit. Selalu mengarah menjauh dari Part0. |
| RelativeVelocity | Vector3 | Kecepatan Part1 relatif terhadap Part0 di titik kontak, diukur sebelum solver menyelesaikan tabrakan. |
| Area | number | Perkiraan area dari area kontak. |
Untuk mendapatkan kecepatan dampak langsung, ambil produk titik dari RelativeVelocity dan Normal. Untuk mendeteksi tabrakan menyamping atau meluncur, gunakan komponen tangensial dari RelativeVelocity. Jika Anda menginginkan nilai yang lebih mendekati gaya, gabungkan kecepatan dengan AssemblyMass bagian.
local part = workspace.Part
local function onCollision(summaries)
for _, summary in summaries do
local impactSpeed = summary.RelativeVelocity:Dot(summary.Normal)
if impactSpeed > 10 then
print("Dampak keras di", summary.Point, "dengan kecepatan", impactSpeed)
end
end
end
local connection = part:BindToCollisionSummaries(onCollision)
-- Nanti, ketika Anda tidak lagi memerlukan ringkasan
connection:Disconnect()Perhatikan hal berikut saat Anda menggunakan ringkasan tabrakan:
- Ringkasan hanya dihasilkan pada pemilik jaringan yang menjalankan simulasi fisika, yang bisa berupa klien atau server. Mereka tidak direplikasi. Jika klien lain perlu mengetahui tentang sebuah tabrakan, proses ringkasan dan kirim hanya data yang mereka butuhkan melalui peristiwa jarak jauh.
- Bagian dengan CanCollide diatur ke false tidak menghasilkan ringkasan tabrakan.
- Bagian non-konveks yang kompleks dapat menghasilkan lebih dari satu ringkasan untuk pasangan bagian yang sama.
- Kontak antara dua bagian yang tidur tidak dicatat.
- Biaya pemrosesan meningkat seiring dengan jumlah bagian yang disubscribe, bukan dengan total jumlah tabrakan di tempat.
Penyaringan tabrakan
Penyaringan tabrakan mendefinisikan bagian fisik mana yang bertabrakan dengan yang lain. Anda dapat mengonfigurasi penyaringan untuk banyak objek melalui grup tabrakan atau Anda dapat mengontrol tabrakan pada basis bagian-ke-bagian dengan instance NoCollisionConstraint.
Grup tabrakan
Grup tabrakan memungkinkan Anda menetapkan BaseParts ke grup yang ditentukan dan menentukan apakah mereka bertabrakan dengan yang ada di grup lain. Bagian dalam grup yang tidak bertabrakan melewati satu sama lain sepenuhnya, bahkan jika kedua bagian memiliki properti CanCollide diatur ke true. Grup tabrakan dibuat dan dikonfigurasi berdasarkan Workspace atau WorldModel.
Anda dapat dengan mudah mengatur grup tabrakan melalui editor Grup Tabrakan di Studio, yang dapat diakses melalui menu Jendela ⟩ 3D di Studio.
Daftarkan grup
Workspace menyimpan status grup tabrakan yang dapat dikonfigurasi sendiri. Selain itu, setiap WorldModel dapat memilih untuk menggunakan grup tabrakan mereka sendiri untuk kueri.
Editor ini mencakup satu grup tabrakan Default yang tidak dapat diubah namanya atau dihapus. Semua BaseParts secara otomatis termasuk dalam grup default ini kecuali ditetapkan ke grup lain, yang berarti bahwa mereka akan bertabrakan dengan semua objek lain dalam grup Default.
Untuk membuat grup tabrakan baru:
Secara default, grup terdaftar di Workspace, tetapi jika Anda memiliki setidaknya satu WorldModel di tempat Anda, dropdown pilihan akan muncul di bagian atas editor grup tabrakan. Gunakan dropdown untuk mengonfigurasi grup tabrakan di berbagai instance WorldModel.

Untuk setiap WorldModel, Anda dapat mengaktifkan Gunakan grup tabrakan Workspace untuk membuatnya menggunakan grup tabrakan Workspace untuk kuerinya.

Klik tombol Tambah Grup di bagian atas panel editor, masukkan nama grup baru, dan tekan Enter. Grup baru akan muncul di kedua kolom tampilan daftar, atau di kolom kiri dan baris atas tampilan tabel.

Ulangi proses ini jika perlu, memilih nama yang unik dan deskriptif untuk setiap grup. Perhatikan bahwa Anda dapat mengubah nama grup selama pengembangan dengan mengklik di bidangnya, atau dengan memilihnya dan mengklik tombol ubah nama.

Konfigurasi tabrakan grup
Di bawah konfigurasi default, objek dalam semua grup bertabrakan satu sama lain. Untuk mencegah objek dalam satu grup bertabrakan dengan objek dalam grup lain, hapus centang kotak di baris/kolom yang sesuai.
Dalam contoh berikut, objek dalam grup Cubes tidak akan bertabrakan dengan objek dalam grup Doors.

Menetapkan objek ke grup
Untuk menetapkan objek ke grup yang telah Anda daftarkan melalui editor Studio:
Pilih satu atau lebih BaseParts yang memenuhi syarat sebagai bagian dari grup tabrakan.
Tetapkan mereka ke grup dengan mengklik tombol ⊕ untuk barisnya. Objek hanya dapat menjadi bagian dari satu grup tabrakan pada satu waktu, jadi menempatkan mereka dalam grup baru akan menghapus mereka dari grup saat ini.

Setelah ditetapkan, grup baru akan tercermin di properti CollisionGroup objek.

Grup StudioSelectable
Alat di Studio menggunakan sistem penyaringan tabrakan untuk menentukan objek mana yang menjadi kandidat untuk dipilih saat mengklik di viewport 3D. Objek yang grup tabrakannya ditetapkan tidak bertabrakan dengan StudioSelectable akan diabaikan.
Sebagai contoh, jika Anda memiliki checkpoint dalam permainan balap yang area efektifnya didefinisikan oleh bagian transparan besar, Anda dapat menetapkannya ke grup tabrakan Checkpoints dan kemudian membuat grup tersebut tidak dapat bertabrakan dengan StudioSelectable sehingga tidak mengganggu saat Anda mengedit geometri peta yang mendasarinya.

Untuk kode plugin, disarankan agar Anda menetapkan "StudioSelectable" sebagai penyaring grup tabrakan dari RaycastParams Anda saat mencari bagian di bawah kursor. Ini memungkinkan plugin Anda untuk mencocokkan mekanika pemilihan yang telah dipelajari oleh pembuat untuk diharapkan dari alat Studio bawaan.
local UserInputService = game:GetService("UserInputService")
local raycastParams = RaycastParams.new()
raycastParams.CollisionGroup = "StudioSelectable" -- Untuk mengikuti konvensi
raycastParams.BruteForceAllSlow = true -- Agar bagian dengan CanQuery "false" dapat dipilih
local mouseLocation = UserInputService:GetMouseLocation()
local mouseRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
local filteredSelectionHit = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 10000, raycastParams)Penyaringan bagian-ke-bagian
Untuk mencegah tabrakan antara dua bagian tertentu tanpa menyiapkan grup tabrakan, seperti antara roda kendaraan dan sasisnya, pertimbangkan keterbatasan No Collision. Keuntungannya termasuk:
- Grup tabrakan dan/atau skrip konfigurasi tidak diperlukan, sehingga Anda dapat dengan mudah membuat dan membagikan model dengan penyaringan tabrakan yang disesuaikan.
- Bagian yang terhubung tidak akan bertabrakan satu sama lain, tetapi mereka masih dapat bertabrakan dengan objek lain.
Nonaktifkan tabrakan karakter
Karakter pemain Roblox bertabrakan satu sama lain secara default. Ini dapat menyebabkan permainan yang menarik tetapi tidak diinginkan, seperti karakter melompat di atas satu sama lain untuk mencapai area tertentu. Jika perilaku ini tidak diinginkan, Anda dapat mencegahnya melalui Script berikut di ServerScriptService.
local Players = game:GetService("Players")
workspace:RegisterCollisionGroup("Characters")
workspace:CollisionGroupSetCollidable("Characters", "Characters", false)
local function onDescendantAdded(descendant)
-- Atur grup tabrakan untuk setiap bagian keturunan
if descendant:IsA("BasePart") then
descendant.CollisionGroup = "Characters"
end
end
local function onCharacterAdded(character)
-- Proses keturunan yang ada dan baru untuk pengaturan fisika
for _, descendant in character:GetDescendants() do
onDescendantAdded(descendant)
end
character.DescendantAdded:Connect(onDescendantAdded)
end
Players.PlayerAdded:Connect(function(player)
-- Deteksi ketika karakter pemain ditambahkan
player.CharacterAdded:Connect(onCharacterAdded)
end)Tabrakan model
Objek Model adalah wadah untuk bagian daripada mewarisi dari BasePart, sehingga mereka tidak dapat terhubung langsung ke peristiwa BasePart.Touched atau BasePart.TouchEnded. Untuk menentukan apakah sebuah model memicu peristiwa tabrakan, Anda perlu melakukan loop melalui anak-anaknya dan menghubungkan fungsi kustom onTouched() dan onTouchEnded() ke setiap anak BasePart.
Contoh kode berikut menghubungkan semua BaseParts dari model multi-bagian ke peristiwa tabrakan dan melacak jumlah total tabrakan dengan bagian lain.
local model = script.Parent
local numTouchingParts = 0
local function onTouched(otherPart)
-- Abaikan instance model yang berinteraksi dengan dirinya sendiri
if otherPart:IsDescendantOf(model) then return end
-- Tingkatkan jumlah bagian model yang bersentuhan
numTouchingParts += 1
print(model.Name, "berinteraksi dengan", otherPart.Name, "| Bagian model yang bersentuhan:", numTouchingParts)
end
local function onTouchEnded(otherPart)
-- Abaikan instance model yang tidak berinteraksi dengan dirinya sendiri
if otherPart:IsDescendantOf(model) then return end
-- Kurangi jumlah bagian model yang bersentuhan
numTouchingParts -= 1
print(model.Name, "tidak berinteraksi lagi dengan", otherPart.Name, "| Bagian model yang bersentuhan:", numTouchingParts)
end
for _, child in model:GetChildren() do
if child:IsA("BasePart") then
child.Touched:Connect(onTouched)
child.TouchEnded:Connect(onTouchEnded)
end
endTabrakan mesh dan model padat
MeshPart dan PartOperation (bagian yang digabungkan melalui pemodelan padat) adalah subclass dari BasePart, sehingga bagian mesh dan model padat mewarisi opsi peristiwa tabrakan dan penyaringan tabrakan yang sama seperti bagian biasa. Namun, karena bagian mesh dan model padat biasanya memiliki geometri yang lebih kompleks, mereka memiliki properti CollisionFidelity yang menentukan seberapa tepat batas fisik sejajar dengan representasi visual untuk penanganan tabrakan.
Properti CollisionFidelity memiliki opsi berikut, dalam urutan fidelitas dan dampak kinerja dari yang terendah hingga tertinggi:
- Box — Membuat kotak tabrakan pembatas, ideal untuk objek kecil atau tidak interaktif.
- Hull — Menghasilkan cangkang konveks, cocok untuk objek dengan lekukan atau rongga yang kurang mencolok.
- Default — Menghasilkan bentuk tabrakan perkiraan yang mendukung kekonkavan, cocok untuk objek kompleks dengan kebutuhan interaksi semi-rinci.
- PreciseConvexDecomposition — Menawarkan fidelitas paling tepat tetapi tetap bukan representasi 1:1 dari visual. Opsi ini memiliki biaya kinerja paling mahal dan memerlukan waktu lebih lama bagi mesin untuk menghitung.

Untuk informasi lebih lanjut tentang dampak kinerja dari opsi fidelitas tabrakan dan cara menguranginya, lihat optimasi kinerja.