Instansi DragDetector memfasilitasi dan mendorong interaksi dengan objek 3D dalam permainan, 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 BasePart atau Model mana pun untuk membuatnya dapat diseret melalui semua input (mouse, sentuhan, gamepad, dan VR), semuanya tanpa satu baris kode pun.
Pilih dari beberapa gaya seret, tentukan bagaimana objek merespons gerakan, dan secara opsional terapkan batas sumbu atau gerakan.
Skrip dapat merespons manipulasi objek yang diseret untuk menggerakkan UI atau membuat keputusan logis, seperti menyesuaikan tingkat cahaya di sebuah ruangan berdasarkan dimmer saklar dinding yang geser.
Pemain dapat memanipulasi bagian atau model yang terikat dan mereka akan tetap persis di tempat Anda meletakkannya setelah dilepaskan.
DragDetectors bekerja di Studio selama Anda tidak menggunakan alat Pilih, Gerakkan, Skala, atau Putar, sehingga lebih mudah untuk menguji dan menyesuaikan objek yang dapat diseret saat mengedit.
Membuat objek dapat diseret
Untuk membuat bagian atau model apa pun dapat diseret, cukup tambahkan DragDetector sebagai keturunan langsung.
Dari menu, masukkan DragDetector.

Secara default, objek sekarang akan dapat diseret di bidang tanah, tetapi Anda dapat menyesuaikan DragStyle-nya, menentukan bagaimana objek merespons gerakan, dan secara opsional menerapkan batas sumbu atau gerakan.
Kustomisasi 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 berbagai pemetaan untuk memenuhi kebutuhan Anda. Misalnya, TranslatePlane menghasilkan translasi di bidang virtual, sedangkan RotateAxis menghasilkan rotasi di sekitar sumbu virtual.
| Pengaturan | Deskripsi |
|---|---|
| TranslateLine | Gerakan 1D sepanjang Axis detektor, secara default sumbu Y dunia. |
| TranslatePlane | Gerakan 2D di bidang yang tegak lurus terhadap Axis detektor, secara default bidang XZ dunia. |
| TranslatePlaneOrLine | Gerakan 2D di bidang yang tegak lurus terhadap 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 terhadap Axis detektor. |
| TranslateViewPlane | Gerakan 2D di bidang yang tegak lurus terhadap pandangan kamera. Dalam mode ini, bidang diperbarui secara konstan, bahkan saat diseret, dan akan selalu menghadap pandangan kamera saat ini. |
| RotateAxis | Rotasi di sekitar 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 kustom yang disediakan melalui SetDragStyleFunction(). |
Arah seret
Secara default, gerakan 3D dan DragStyle 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 porosnya 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 ke arah (atau di bidang yang tegak lurus terhadap) properti Axis di 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 telah diorientasikan 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 Terikat | Perilaku Tidak Terikat |
|---|---|---|
| Geometric | Baik di dalam permainan 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 dengan objek yang terikat. Namun, dalam permainan yang sedang berjalan, objek akan terikat pada awal seret dan dipulihkan menjadi tidak terikat saat seret dilepaskan. |
| Physical | Objek yang terikat akan default ke perilaku Geometric, karena tidak terpengaruh oleh gaya. | Objek yang tidak terikat akan dipindahkan oleh gaya pembatas yang berusaha membawanya ke posisi dan/atau orientasi yang diinginkan yang diberikan oleh gerakan yang diusulkan. |
| Custom | Objek tidak akan bergerak sama sekali, tetapi DragFrame masih akan diperbarui dan Anda dapat merespons manipulasi seret sesuai keinginan Anda. | (sama seperti 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. Namun, perlu dicatat bahwa ini bukan batasan; mereka hanya menghalangi upaya detektor seret untuk menghasilkan gerakan agar tetap dalam batas.
| Properti | Deskripsi | Default |
|---|---|---|
| MinDragTranslation MaxDragTranslation | Batas untuk translasi seret di setiap dimensi. Jika MaxDragTranslation lebih besar dari MinDragTranslation, translasi akan dibatasi dalam rentang tersebut. | (0, 0, 0) |
| MinDragAngle MaxDragAngle | Hanya relevan jika DragStyle diatur 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 diatur 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 untuk mendaftarkan fungsi atau mengembalikan hasil yang tidak valid akan mencegah semua pemain dari seret. |
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 detektor diatur ke Physical dan diterapkan pada objek yang tidak terikat, objek tersebut akan dipindahkan oleh gaya pembatas 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 di mana pengguna mengklik. Ketika true, gaya diterapkan di pusat massa objek. | false |
| MaxForce | Gaya maksimum yang diterapkan agar objek mencapai tujuannya. | 10000000 |
| MaxTorque | Torsi maksimum 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/kolom 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 properti dari instansi detektor seret.
Replikasi
Ketika properti RunLocally adalah 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 berada di server Scripts.
Ketika properti RunLocally adalah true, tidak ada acara yang direplikasi ke server. Semua sinyal acara kustom dan fungsi yang terdaftar harus berada di klien 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 menggerakkan UI atau membuat keputusan logis, seperti menyesuaikan tingkat cahaya di sebuah ruangan berdasarkan dimmer saklar dinding yang geser.
Sinyal acara
Melalui sinyal acara berikut, Anda dapat mendeteksi kapan pengguna mulai, melanjutkan, dan menghentikan seret objek.
| Acara | Deskripsi |
|---|---|
| DragStart | Dipicu ketika pengguna mulai menyeret objek. |
| DragContinue | Dipicu ketika pengguna melanjutkan menyeret objek setelah DragStart telah dimulai. |
| DragEnd | Dipicu ketika pengguna berhenti menyeret objek. |
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 bingkai seret
Selain sinyal acara, Anda dapat memantau perubahan pada DragFrame detektor secara langsung.
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)Gaya seret yang diprogram
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 sehingga objek yang diseret pergi ke lokasi/orientasi kustom tersebut.
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)
-- Kecualikan 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 peningkatan grid, atau mensimulasikan permainan catur dengan aturan gerakan yang sah untuk setiap bidak.
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)
-- Ketika 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 menjaga 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 membagikan 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 apa yang ada 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 bersama. Menggerakkan pegangan dengan gaya seret TranslateViewPlane DragStyle membuat marionette menari, dan bagian tubuh individu juga dapat dipindahkan dengan detektor seret, semuanya sementara model mempertahankan integritasnya.
Antarmuka pengguna 3D
Antarmuka pengguna 3D dapat dengan mudah dicapai melalui detektor seret, seperti menyesuaikan kecerahan SpotLight berdasarkan dimmer saklar yang geser. Anda juga dapat mendeteksi sumbu X dan Z secara individual untuk mengontrol dua aspek berbeda dari antarmuka pengguna 3D, seperti Size, Speed, dan Color dari ParticleEmitter.
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 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)