Instansi DragDetector memfasilitasi dan mendorong interaksi dengan objek 3D dalam pengalaman, seperti membuka pintu dan laci, menggeser bagian, mengambil dan melempar bola bowling, menarik kembali dan menembakkan ketapel, dan banyak lagi. Fitur utama termasuk:
Tempatkan DragDetector di bawah setiap BasePart atau Model untuk membuatnya dapat diseret melalui semua input (mouse, sentuhan, gamepad, dan VR), semuanya tanpa satu baris kode pun.
Pilih dari beberapa gaya seret, definisikan bagaimana objek merespons gerakan, dan secara opsional terapkan batas sumbu atau gerakan.
Skrip dapat merespons manipulasi objek yang diseret untuk mengendalikan UI atau membuat keputusan logis, seperti mengatur level cahaya di sebuah ruangan berdasarkan dimmer saklar dinding yang meluncur.
Pemain dapat memanipulasi bagian atau model yang terikat dan mereka akan tetap persis di tempat Anda meletakkannya setelah dilepas.
DragDetectors bekerja di Studio selama Anda tidak menggunakan alat Select, Move, Scale, atau Rotate, membuatnya lebih mudah untuk menguji dan menyesuaikan objek yang dapat diseret saat mengedit.
Membuat objek dapat diseret
Untuk membuat bagian atau model dapat diseret, cukup tambahkan DragDetector sebagai keturunan langsung.
Dari menu tersebut, masukkan DragDetector.

Secara default, objek sekarang akan dapat diseret di bidang tanah, tetapi Anda dapat menyesuaikan DragStyle-nya, mendefinisikan bagaimana ia merespons gerakan, dan secara opsional menerapkan batas sumbu atau gerakan.
Sesuaikan detektor seret
Gaya seret
DragDetectors memetakan gerakan kursor ke garis dan bidang virtual untuk menghitung gerakan 3D yang diusulkan. Melalui properti DragStyle, Anda dapat memilih dari pemetaan yang berbeda sesuai dengan kebutuhan Anda. Misalnya, TranslatePlane menghasilkan translasi di bidang virtual, sedangkan RotateAxis menghasilkan rotasi tentang sumbu virtual.
| Pengaturan | Deskripsi |
|---|---|
| TranslateLine | Gerakan 1D sepanjang Axis detektor, secara default sumbu Y dunia. |
| TranslatePlane | Gerakan 2D di bidang yang tegak lurus dengan Axis detektor, secara default bidang XZ dunia. |
| TranslatePlaneOrLine | Gerakan 2D di bidang yang tegak lurus dengan Axis detektor dan, ketika modifikator aktif, gerakan 1D sepanjang Axis detektor. |
| TranslateLineOrPlane | Gerakan 1D sepanjang Axis detektor dan, ketika modifikator aktif, gerakan 2D di bidang yang tegak lurus dengan Axis detektor. |
| TranslateViewPlane | Gerakan 2D di bidang yang tegak lurus dengan pandangan kamera. Dalam mode ini, bidang selalu diperbarui, bahkan saat menyeret, dan akan selalu menghadap pandangan kamera saat ini. |
| RotateAxis | Rotasi tentang Axis detektor, secara default sumbu Y dunia. |
| RotateTrackball | Rotasi trackball, lebih lanjut disesuaikan melalui properti TrackballRadialPullFactor dan TrackballRollFactor. |
| BestForDevice | TranslatePlaneOrLine untuk mouse dan gamepad; TranslatePlane untuk sentuhan; 6DOF untuk VR. |
| Scriptable | Menghitung gerakan yang diinginkan melalui fungsi khusus yang diberikan melalui SetDragStyleFunction(). |
Arah seret
Secara default, gerakan 3D dan DragStyle yang terkait dipetakan ke ruang dunia. Namun, Anda mungkin ingin mengubah ReferenceInstance, Orientation, atau Axis, misalnya saat membangun detektor seret ke dalam model dengan bagian yang dapat disesuaikan.
| Properti | Deskripsi | Default |
|---|---|---|
| ReferenceInstance | Sebuah instansi yang pivotnya menyediakan kerangka referensi untuk detektor seret. DragFrame dinyatakan relatif terhadap kerangka referensi ini yang dapat diambil melalui GetReferenceFrame(). Jika kerangka referensi adalah nil, translasi akan dilakukan dalam arah (atau dalam bidang yang tegak lurus dengan) properti Axis dalam ruang dunia. | nil |
| Orientation | Menentukan rotasi YXZ sumbu gerakan relatif terhadap kerangka referensi (tidak mengubah orientasi kerangka referensi itu sendiri). Translasi linier dan rotasi sumbu akan berada di sumbu Y yang diputar ulang ini, dan translasi planar di bidang XZ. Mengubah nilai ini secara otomatis memperbarui Axis dan sebaliknya. | (0, 0, 0) |
| Axis | Sumbu utama gerakan, dinyatakan relatif terhadap kerangka referensi. Mengubah nilai ini secara otomatis memperbarui Orientation dan sebaliknya. | (0, 1, 0) |
Respons terhadap gerakan
Properti ResponseStyle menentukan bagaimana objek merespons gerakan yang diusulkan, tergantung pada apakah objek tersebut Anchored atau tidak.
| Pengaturan | Perilaku Terkait | Perilaku Tidak Terkait |
|---|---|---|
| Geometric | Baik di dalam pengalaman yang sedang berjalan maupun dalam mode edit Studio, posisi/orientasi objek yang terikat akan diperbarui untuk mencerminkan dengan tepat gerakan yang diusulkan. | Untuk objek yang tidak terikat, perilakunya sama seperti objek yang terikat. Namun, dalam pengalaman yang sedang berjalan, objek ini akan terikat di awal seretan dan dipulihkan ke status tidak terikat saat seretan dilepaskan. |
| Physical | Objek yang terikat akan default ke perilaku Geometric, karena tidak terpengaruh oleh gaya. | Objek yang tidak terikat akan dipindahkan oleh gaya batas yang berusaha membawanya ke posisi/orientasi yang diinginkan yang diberikan oleh gerakan yang diusulkan. |
| Custom | Objek tidak akan bergerak sama sekali, tetapi DragFrame tetap akan diperbarui dan Anda dapat merespons manipulasi seret sesuka Anda. | (sama dengan terikat) |
Batas sumbu & gerakan
Secara default, tidak ada batasan untuk gerakan 3D di luar batasan bawaan dari DragStyle. Jika perlu, Anda dapat menerapkan batas minimum dan maksimum untuk translasi dan rotasi. Perhatikan, bagaimanapun, bahwa ini bukan batasan; mereka hanya menghalangi upaya detektor seret untuk menghasilkan gerakan agar tetap dalam batas.
| Properti | Deskripsi | Default |
|---|---|---|
| Membatasi translasi seret di setiap dimensi. Jika MaxDragTranslation lebih besar dari MinDragTranslation, translasi akan dibatasi dalam rentang tersebut. | (0, 0, 0) | |
| Hanya relevan jika DragStyle disetel ke RotateAxis. Jika MaxDragAngle lebih besar dari MinDragAngle, rotasi akan dibatasi dalam rentang tersebut. | 0 |
Izin seret
Izin pemain untuk berinteraksi dengan instansi detektor seret tertentu dapat ditentukan oleh properti PermissionPolicy. Ini disetel ke Enum.DragDetectorPermissionPolicy.Everybody secara default, dan juga dapat diubah untuk mendukung kontrol izin yang diprogram seperti yang ditunjukkan dalam contoh kode.
| Pengaturan | Deskripsi |
|---|---|
| Nobody | Tidak ada pemain yang dapat berinteraksi dengan DragDetector. |
| Everybody | Semua pemain dapat berinteraksi dengan DragDetector. |
| Scriptable | Izin seret pemain akan ditentukan oleh fungsi yang terdaftar melalui SetPermissionPolicyFunction(). Di bawah pengaturan ini, kegagalan mendaftarkan fungsi atau mengembalikan hasil yang tidak valid akan mencegah semua pemain dari melakukan seret. |
DragDetector - Izin Seret Terprogram
local dragDetector = script.Parent.DragDetector
dragDetector.PermissionPolicy = Enum.DragDetectorPermissionPolicy.Scriptable
dragDetector:SetPermissionPolicyFunction(function(player, part)
if player and player:GetAttribute("IsInTurn") then
return true
elseif part and not part:GetAttribute("IsDraggable") then
return false
else
return true
end
end)
Respons fisika
Dengan asumsi gaya respons dari detektor disetel ke Physical dan diterapkan pada objek yang tidak terikat, objek itu akan dipindahkan oleh gaya batas yang berusaha membawanya ke posisi/orientasi yang diberikan oleh gerakan yang diusulkan. Anda dapat lebih menyesuaikan respons fisik melalui properti berikut:
| Properti | Deskripsi | Default |
|---|---|---|
| ApplyAtCenterOfMass | Ketika false, gaya seret diterapkan pada titik yang diklik pengguna. Ketika true, gaya diterapkan di pusat massa objek. | false |
| MaxForce | Besar maksimum gaya yang diterapkan agar objek mencapai tujuannya. | 10000000 |
| MaxTorque | Besar maksimum torsi yang diterapkan agar objek mencapai tujuannya. | 10000 |
| Responsiveness | Nilai yang lebih tinggi menyebabkan objek mencapai tujuannya lebih cepat. | 10 |
Input modifikator
Beberapa mode DragStyle memungkinkan pengguna untuk menahan tombol/yang menjadi modifikator untuk memanipulasi objek yang diseret dengan cara yang berbeda. Secara default, modifikator adalah LeftControl di PC, ButtonR1 di gamepad, atau ButtonL2 di VR. Anda dapat menyesuaikan modifikator ini melalui KeyboardModeSwitchKeyCode, GamepadModeSwitchKeyCode, atau VRSwitchKeyCode dari instansi detektor seret.
Replikasi
Ketika properti RunLocally false (default), klien menginterpretasikan semua input untuk menghasilkan data yang dikirim ke server untuk melakukan seret. Dalam mode ini, semua sinyal acara kustom dan fungsi yang terdaftar harus ada di server Scripts.
Ketika properti RunLocally true, tidak ada acara yang direplikasi ke server. Semua sinyal acara kustom dan fungsi yang terdaftar harus ada di client LocalScripts dan Anda harus menggunakan acara jarak jauh untuk menyebarkan perubahan yang diperlukan ke server.
Respons skrip terhadap klik dan seret
Melalui sinyal acara, perubahan properti, gaya seret Scriptable, dan fungsi kustom, skrip dapat merespons manipulasi objek yang diseret untuk mengendalikan UI atau membuat keputusan logis, seperti mengatur level cahaya di sebuah ruangan berdasarkan dimmer saklar dinding yang meluncur.
Sinyal acara
Melalui sinyal acara berikut, Anda dapat mendeteksi kapan seorang pengguna memulai, melanjutkan, dan mengakhiri penyeretan sebuah objek.
| Acara | Deskripsi |
|---|---|
| DragStart | Terpicu ketika pengguna memulai penyeretan objek. |
| DragContinue | Terpicu ketika pengguna melanjutkan penyeretan objek setelah DragStart diinisiasi. |
| DragEnd | Terpicu ketika pengguna berhenti menyeret objek. |
DragDetector - Sinyal Acara
local dragDetector = script.Parent.DragDetector
local highlight = Instance.new("Highlight")
highlight.Enabled = false
highlight.Parent = script.Parent
dragDetector.DragStart:Connect(function()
highlight.Enabled = true
end)
dragDetector.DragContinue:Connect(function()
end)
dragDetector.DragEnd:Connect(function()
highlight.Enabled = false
end)
Perubahan frame seret
Selain sinyal acara, Anda dapat memantau perubahan pada DragFrame detektor secara langsung.
DragDetector - Perubahan DragFrame
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)
Gaya seret terprogram
Jika Anda mengatur DragStyle detektor ke Scriptable, Anda dapat menyediakan fungsi Anda sendiri yang menerima Ray dan mengembalikan CFrame ruang dunia. Detektor akan memindahkan gerakan agar objek yang diseret menuju lokasi/orientasi kustom tersebut.
DragDetector - Gaya Seret Terprogram
local Workspace = game:GetService("Workspace")
local dragDetector = script.Parent.DragDetector
dragDetector.DragStyle = Enum.DragDetectorDragStyle.Scriptable
local cachedHitPoint = Vector3.zero
local cachedHitNormal = Vector3.yAxis
local function followTheCursor(cursorRay)
-- Tidak termasuk objek yang diseret dari deteksi raycast
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {dragDetector.Parent}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local hitPoint = Vector3.zero
local hitNormal = Vector3.yAxis
local raycastResult = Workspace:Raycast(cursorRay.Origin, cursorRay.Direction, raycastParams)
if raycastResult then
hitPoint = raycastResult.Position
hitNormal = raycastResult.Normal.Unit
else
hitPoint = cachedHitPoint
hitNormal = cachedHitNormal
end
cachedHitPoint = hitPoint
cachedHitNormal = hitNormal
local lookDir1 = hitNormal:Cross(Vector3.xAxis)
local lookDir2 = hitNormal:Cross(Vector3.yAxis)
local lookDir = if lookDir1.Magnitude > lookDir2.Magnitude then lookDir1.Unit else lookDir2.Unit
return CFrame.lookAt(hitPoint, hitPoint + lookDir, hitNormal)
end
dragDetector:SetDragStyleFunction(followTheCursor)
Fungsi batasan kustom
Detektor seret tidak memiliki aturan gerakan bawaan tentang grid dan snapping, tetapi Anda dapat mendaftarkan fungsi batasan kustom untuk mengedit DragFrame detektor sebelum diterapkan. Misalnya, Anda dapat menjaga gerakan pada grid dengan membulatkan posisi ke kelipatan dari increment grid, atau mensimulasikan permainan catur dengan aturan gerakan yang sah untuk setiap pion.
DragDetector - Fungsi Batasan Kustom
local dragDetector = script.Parent.DragDetector
local startPartPosition = nil
local SNAP_INCREMENT = 4
dragDetector.DragStart:Connect(function()
startPartPosition = script.Parent.Position
end)
dragDetector.DragEnd:Connect(function()
startPartPosition = nil
end)
local function snapToWorldGrid(proposedMotion)
if startPartPosition == nil then
return proposedMotion
end
local snapIncrement = SNAP_INCREMENT // 1
if snapIncrement < 1 then
return proposedMotion
end
local newWorldPosition = startPartPosition + proposedMotion.Position
local roundedX = ((newWorldPosition.X / snapIncrement + 0.5) // 1) * snapIncrement
local roundedY = ((newWorldPosition.Y / snapIncrement + 0.5) // 1) * snapIncrement
local roundedZ = ((newWorldPosition.Z / snapIncrement + 0.5) // 1) * snapIncrement
local newRoundedWorldPosition = Vector3.new(roundedX, roundedY, roundedZ)
return proposedMotion.Rotation + (newRoundedWorldPosition - startPartPosition)
end
local connection = dragDetector:AddConstraintFunction(2, snapToWorldGrid)
-- Saat berlaku, hapus fungsi batasan dengan memanggil connection:Disconnect()
Contoh penggunaan
Objek fisik yang tidak terikat
Implementasi dasar dari detektor seret adalah permainan keseimbangan menara di mana pemain harus hati-hati menghapus bagian dan berusaha mempertahankan menara tetap tegak. Dalam struktur menara berikut, setiap bagian memiliki anak DragDetector dengan DragStyle default TranslatePlane sehingga pemain dapat menarik bagian ke luar tetapi tidak ke atas atau ke bawah.
Model terikat dengan bagian yang dapat disesuaikan
Anda dapat dengan mudah membuat dan berbagi model yang sebagian besar terikat, tetapi memiliki satu atau lebih bagian/model anak yang dapat diseret oleh pemain. Misalnya, meja berikut memiliki dua laci yang dapat dibuka pemain untuk memeriksa isi di dalamnya.
Detektor seret dan batasan
Anda dapat menggabungkan detektor seret dengan Constraints, misalnya boneka marionette. Dalam pengaturan berikut, pegangan kontrol terikat, bagian tubuh tidak terikat, dan batasan menjaga marionette tetap bersatu. Menggerakkan pegangan dengan gaya seret TranslateViewPlane DragStyle membuat marionette bergerak, dan bagian-bagian tubuh individu juga dapat dipindahkan dengan detektor seret, semua sementara model tetap utuh.
Antarmuka pengguna 3D
Antarmuka pengguna 3D dapat dengan mudah dicapai melalui detektor seret, seperti mengatur kecerahan dari SpotLight berdasarkan dimmer saklar geser. Anda juga dapat mendeteksi sumbu X dan Z secara individual untuk mengendalikan dua aspek berbeda dari antarmuka pengguna 3D, seperti Size, Speed, dan Color dari ParticleEmitter.
DragDetector - Antarmuka Pengguna 3D
local model = script.Parent
local slider = model.SliderPart
local originPart = model.OriginPart
local emitter = script.Parent.EmitterPart.ParticleEmitter
local dragDetector = slider.DragDetector
dragDetector.ReferenceInstance = originPart
dragDetector.MinDragTranslation = Vector3.zero
dragDetector.MaxDragTranslation = Vector3.new(10, 0, 10)
local dragRangeX = dragDetector.MaxDragTranslation.X - dragDetector.MinDragTranslation.X
local dragRangeZ = dragDetector.MaxDragTranslation.Z - dragDetector.MinDragTranslation.Z
local MIN_PARTICLE_SIZE = 1
local MAX_PARTICLE_SIZE = 1.5
local MIN_PARTICLE_SPEED = 2.5
local MAX_PARTICLE_SPEED = 5
local COLOR1 = Color3.fromRGB(255, 150, 0)
local COLOR2 = Color3.fromRGB(255, 0, 50)
local function updateParticles(emitter)
local dragFactorX = (dragDetector.DragFrame.Position.X - dragDetector.MinDragTranslation.X) / dragRangeX
local dragFactorZ = (dragDetector.DragFrame.Position.Z - dragDetector.MinDragTranslation.Z) / dragRangeZ
-- Sesuaikan ukuran dan kecepatan partikel berdasarkan faktor X detektor seret
emitter.Size = NumberSequence.new{
NumberSequenceKeypoint.new(0, 0),
NumberSequenceKeypoint.new(0.1, MIN_PARTICLE_SIZE + ((MAX_PARTICLE_SIZE - MIN_PARTICLE_SIZE) * dragFactorX)),
NumberSequenceKeypoint.new(1, 0)
}
local speed = MIN_PARTICLE_SPEED + ((MAX_PARTICLE_SPEED - MIN_PARTICLE_SPEED) * dragFactorX)
emitter.Speed = NumberRange.new(speed, speed * 1.2)
-- Sesuaikan warna partikel berdasarkan faktor Z dari detektor seret
local color = COLOR2:Lerp(COLOR1, dragFactorZ)
emitter.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, color),
ColorSequenceKeypoint.new(1, color)
}
end
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
updateParticles(emitter)
end)