L'istanza DragDetector facilita e incoraggia l'interazione con oggetti 3D in un gioco, come aprire porte e cassetti, far scorrere una parte, afferrare e lanciare una palla da bowling, tirare indietro e sparare con una fionda, e molto altro. Le caratteristiche principali includono:
Posiziona un DragDetector sotto qualsiasi BasePart o Model per renderlo trascinabile tramite tutti gli input (mouse, tocco, gamepad e VR), il tutto senza una sola riga di codice.
Scegli tra diversi stili di trascinamento, definisci come l'oggetto risponde al movimento e applica facoltativamente limiti sugli assi o sul movimento.
Gli script possono rispondere alla manipolazione degli oggetti trascinati per guidare l'interfaccia utente o prendere decisioni logiche, come regolare il livello di luce in una stanza in base a un dimmer a muro scorrevole.
I giocatori possono manipolare parti o modelli ancorati e rimarranno esattamente dove li hai posizionati al rilascio.
DragDetectors funzionano in Studio finché non stai utilizzando gli strumenti Seleziona, Sposta, Scala o Ruota, rendendo più facile testare e regolare oggetti trascinabili durante la modifica.
Rendi gli oggetti trascinabili
Per rendere qualsiasi parte o modello trascinabile, basta aggiungere un DragDetector come discendente diretto.
Dal menu, inserisci un DragDetector.

Per impostazione predefinita, l'oggetto sarà ora trascinabile nel piano di terra, ma puoi personalizzare il suo DragStyle, definire come risponde al movimento e applicare facoltativamente limiti sugli assi o sul movimento.
Personalizza i rilevatori di trascinamento
Stile di trascinamento
DragDetectors mappano il movimento del cursore a linee e piani virtuali per calcolare il movimento 3D proposto. Tramite la proprietà DragStyle, puoi scegliere tra diverse mappature per soddisfare le tue esigenze. Ad esempio, TranslatePlane produce traduzione in un piano virtuale, mentre RotateAxis produce rotazione attorno a un asse virtuale.
| Impostazione | Descrizione |
|---|---|
| TranslateLine | Movimento 1D lungo l'Axis del rilevatore, per impostazione predefinita l'asse Y del mondo. |
| TranslatePlane | Movimento 2D nel piano perpendicolare all'Axis del rilevatore, per impostazione predefinita il piano XZ del mondo. |
| TranslatePlaneOrLine | Movimento 2D nel piano perpendicolare all'Axis del rilevatore e, quando il modificatore è attivo, movimento 1D lungo l'Axis del rilevatore. |
| TranslateLineOrPlane | Movimento 1D lungo l'Axis del rilevatore e, quando il modificatore è attivo, movimento 2D nel piano perpendicolare all'Axis del rilevatore. |
| TranslateViewPlane | Movimento 2D nel piano perpendicolare alla vista della telecamera. In questa modalità, il piano viene costantemente aggiornato, anche durante il trascinamento, e sarà sempre rivolto verso la vista attuale della telecamera. |
| RotateAxis | Rotazione attorno all'Axis del rilevatore, per impostazione predefinita l'asse Y del mondo. |
| RotateTrackball | Rotazione trackball, ulteriormente personalizzata tramite le proprietà TrackballRadialPullFactor e TrackballRollFactor. |
| BestForDevice | TranslatePlaneOrLine per mouse e gamepad; TranslatePlane per tocco; 6DOF per VR. |
| Scriptable | Calcola il movimento desiderato tramite una funzione personalizzata fornita tramite SetDragStyleFunction(). |
Direzione di trascinamento
Per impostazione predefinita, il movimento 3D e il relativo DragStyle si mappano nello spazio del mondo. Tuttavia, potresti voler cambiare l'ReferenceInstance, l'Orientation o l'Axis, ad esempio quando costruisci rilevatori di trascinamento in modelli con parti regolabili.
| Proprietà | Descrizione | Predefinito |
|---|---|---|
| ReferenceInstance | Un'istanza il cui pivot fornisce il quadro di riferimento per il rilevatore di trascinamento. Il DragFrame è espresso rispetto a questo quadro di riferimento che può essere recuperato tramite GetReferenceFrame(). Se il quadro di riferimento è nil, la traduzione sarà nella direzione (o nel piano perpendicolare) della proprietà Axis nello spazio del mondo. | nil |
| Orientation | Specifica la rotazione YXZ degli assi di movimento rispetto al quadro di riferimento (non cambia l'orientamento del quadro di riferimento stesso). La traduzione lineare e la rotazione assiale saranno su questo asse Y riorientato, e la traduzione piana nel piano XZ. Cambiare questo valore aggiorna automaticamente Axis e viceversa. | (0, 0, 0) |
| Axis | L'asse principale di movimento, espresso rispetto al quadro di riferimento. Cambiare questo valore aggiorna automaticamente Orientation e viceversa. | (0, 1, 0) |
Risposta al movimento
La proprietà ResponseStyle specifica come un oggetto risponde al movimento proposto, a seconda che l'oggetto sia Anchored o meno.
| Impostazione | Comportamento ancorato | Comportamento non ancorato |
|---|---|---|
| Geometric | Sia all'interno del gioco in esecuzione che in modalità modifica Studio, la posizione/orientamento di un oggetto ancorato verrà aggiornato per riflettere esattamente il movimento proposto. | Per un oggetto non ancorato, il comportamento è lo stesso di quello di un oggetto ancorato. Tuttavia, in un gioco in esecuzione, l'oggetto sarà ancorato all'inizio del trascinamento e ripristinato a non ancorato al rilascio del trascinamento. |
| Physical | Un oggetto ancorato avrà un comportamento predefinito Geometric, poiché non è influenzato dalle forze. | Un oggetto non ancorato verrà spostato da forze di vincolo che tentano di portarlo nella posizione/orientamento desiderati dati dal movimento proposto. |
| Custom | L'oggetto non si muoverà affatto, ma il DragFrame verrà comunque aggiornato e puoi rispondere alla manipolazione del trascinamento come preferisci. | (stesso comportamento di ancorato) |
Limiti sugli assi e sul movimento
Per impostazione predefinita, non ci sono limiti al movimento 3D oltre le restrizioni intrinseche dello DragStyle. Se necessario, puoi applicare limiti minimi e massimi sia alla traduzione che alla rotazione. Tieni presente, tuttavia, che questi non sono vincoli; impediscono semplicemente ai tentativi del rilevatore di trascinamento di generare movimento per rimanere all'interno dei limiti.
| Proprietà | Descrizione | Predefinito |
|---|---|---|
| MinDragTranslation MaxDragTranslation | Limiti alla traduzione di trascinamento in ciascuna dimensione. Se MaxDragTranslation è maggiore di MinDragTranslation, la traduzione sarà limitata all'interno di quel range. | (0, 0, 0) |
| MinDragAngle MaxDragAngle | Rilevante solo se DragStyle è impostato su RotateAxis. Se MaxDragAngle è maggiore di MinDragAngle, la rotazione sarà limitata all'interno di quel range. | 0 |
Permessi di trascinamento
Il permesso dei giocatori di interagire con una data istanza di rilevatore di trascinamento può essere specificato dalla proprietà PermissionPolicy. Questo è impostato su Enum.DragDetectorPermissionPolicy.Everybody per impostazione predefinita e può anche essere cambiato per supportare controlli di permesso scriptati come mostrato nel campione di codice.
| Impostazione | Descrizione |
|---|---|
| Nobody | Nessun giocatore può interagire con il DragDetector. |
| Everybody | Tutti i giocatori possono interagire con il DragDetector. |
| Scriptable | I permessi di trascinamento dei giocatori saranno determinati da una funzione registrata tramite SetPermissionPolicyFunction(). Con questa impostazione, il mancato registrazione di una funzione o il ritorno di un risultato non valido impedirà a tutti i giocatori di trascinare. |
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)Risposta fisica
Assumendo che lo stile di risposta di un trascinatore sia impostato su Physical e sia applicato a un oggetto non ancorato, quell'oggetto verrà spostato da forze di vincolo che tentano di portarlo nella posizione/orientamento dati dal movimento proposto. Puoi ulteriormente personalizzare la risposta fisica tramite le seguenti proprietà:
| Proprietà | Descrizione | Predefinito |
|---|---|---|
| ApplyAtCenterOfMass | Quando è falso, la forza di trascinamento viene applicata nel punto in cui l'utente fa clic. Quando è vero, la forza viene applicata al centro di massa dell'oggetto. | false |
| MaxForce | Forza massima applicata affinché l'oggetto raggiunga il suo obiettivo. | 10000000 |
| MaxTorque | Massimo momento torcentale applicato affinché l'oggetto raggiunga il suo obiettivo. | 10000 |
| Responsiveness | Valori più alti fanno sì che l'oggetto raggiunga il suo obiettivo più rapidamente. | 10 |
Input modificatore
Alcuni modi di DragStyle consentono agli utenti di tenere premuto un tasto/pulsante modificatore per manipolare l'oggetto trascinato in modi diversi. Per impostazione predefinita, il modificatore è LeftControl su PC, ButtonR1 su gamepad o ButtonL2 su VR. Puoi personalizzare questi modificatori tramite le proprietà KeyboardModeSwitchKeyCode, GamepadModeSwitchKeyCode o VRSwitchKeyCode dell'istanza del rilevatore di trascinamento.
Replicazione
Quando la proprietà RunLocally è falsa (predefinito), il client interpreta tutti gli input per produrre dati che invia al server per eseguire il trascinamento. In questa modalità, tutti i segnali di eventi personalizzati e le funzioni registrate devono trovarsi negli Scripts del server.
Quando la proprietà RunLocally è vera, nessun evento viene replicato al server. Tutti i segnali di eventi personalizzati e le funzioni registrate devono trovarsi negli LocalScripts del client e devi utilizzare eventi remoti per propagare le modifiche necessarie al server.
Risposte degli script ai clic e al trascinamento
Attraverso segnali di eventi, modifiche alle proprietà, stile di trascinamento Scriptable e funzioni personalizzate, gli script possono rispondere alla manipolazione degli oggetti trascinati per guidare l'interfaccia utente o prendere decisioni logiche, come regolare il livello di luce in una stanza in base a un dimmer a muro scorrevole.
Segnali di eventi
Attraverso i seguenti segnali di eventi, puoi rilevare quando un utente inizia, continua e termina di trascinare un oggetto.
| Evento | Descrizione |
|---|---|
| DragStart | Si attiva quando un utente inizia a trascinare l'oggetto. |
| DragContinue | Si attiva quando un utente continua a trascinare l'oggetto dopo che è stato avviato DragStart. |
| DragEnd | Si attiva quando un utente smette di trascinare l'oggetto. |
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)Modifiche al frame di trascinamento
Oltre ai segnali di eventi, puoi monitorare le modifiche al DragFrame del rilevatore direttamente.
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)Stile di trascinamento scriptato
Se imposti lo DragStyle di un rilevatore su Scriptable, puoi fornire la tua funzione che accetta un Ray e restituisce un CFrame nello spazio del mondo. Il rilevatore muoverà il movimento in modo che l'oggetto trascinato vada in quella posizione/orientamento personalizzati.
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)
-- Escludi l'oggetto trascinato dalla rilevazione del 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)Funzione di vincolo personalizzata
I rilevatori di trascinamento non hanno regole di movimento integrate riguardo a griglie e snapping, ma puoi registrare funzioni di vincolo personalizzate per modificare il DragFrame del rilevatore prima che venga applicato. Ad esempio, puoi mantenere il movimento su una griglia arrotondando le posizioni a multipli dell'incremento della griglia, o simulare un gioco di scacchi con regole di movimento legali per ciascun pezzo.
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)
-- Quando applicabile, rimuovi la funzione di vincolo invocando connection:Disconnect()Esempi di utilizzo
Oggetti fisici non ancorati
Un'implementazione di base dei rilevatori di trascinamento è un gioco di equilibrio della torre in cui i giocatori devono rimuovere con attenzione i pezzi e tentare di mantenere la torre in piedi. Nella seguente struttura della torre, ogni pezzo ha un DragDetector figlio con un DragStyle predefinito di TranslatePlane in modo che i giocatori possano tirare i pezzi verso l'esterno ma non verso l'alto o verso il basso.
Modelli ancorati con parti regolabili
Puoi facilmente creare e condividere modelli che sono principalmente ancorati, ma che hanno una o più parti/modelli figli che i giocatori possono trascinare. Ad esempio, la seguente scrivania ha due cassetti che i giocatori possono aprire per ispezionare cosa c'è dentro.
Rilevatori di trascinamento e vincoli
Puoi combinare i rilevatori di trascinamento con Constraints, ad esempio un burattino marionetta. Nella seguente configurazione, le maniglie di controllo sono ancorate, le parti del corpo sono non ancorate e i vincoli tengono insieme la marionetta. Muovere le maniglie con lo DragStyle TranslateViewPlane fa danzare la marionetta, e le singole parti del corpo possono anche essere spostate con i rilevatori di trascinamento, il tutto mentre il modello mantiene la sua integrità.
Interfacce utente 3D
Le interfacce utente 3D sono facilmente realizzabili tramite i rilevatori di trascinamento, come regolare la luminosità di un SpotLight in base a un dimmer a interruttore scorrevole. Puoi anche rilevare gli assi X e Z individualmente per controllare due aspetti diversi di un'interfaccia utente 3D, come la Size, Speed e Color di un 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
-- Regola la dimensione e la velocità delle particelle in base al fattore X del rilevatore di trascinamento
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)
-- Regola il colore delle particelle in base al fattore Z del rilevatore di trascinamento
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)