Die Instanz DragDetector erleichtert und fördert die Interaktion mit 3D-Objekten in einer Erfahrung, wie das Öffnen von Türen und Schubladen, das Verschieben eines Teils, das Greifen und Werfen eines Bowlingballs, das Zurückziehen und Abfeuern einer Schleuder und vieles mehr. Zu den wichtigsten Funktionen gehören:
Platziere einen DragDetector unter jedem BasePart oder Model, um es über alle Eingaben (Maus, Touch, Gamepad und VR) ziehbar zu machen, und das ganz ohne eine einzige Zeile Code.
Wähle aus verschiedenen Ziehen-Stilen, definiere, wie das Objekt auf Bewegungen reagiert, und wende optional Achsen- oder Bewegungsgrenzen an.
Skripts können auf die Manipulation gezogener Objekte reagieren, um die Benutzeroberfläche zu steuern oder logische Entscheidungen zu treffen, wie z. B. das Anpassen der Lichtstärke in einem Raum basierend auf einem schiebenden Wandschalterdimmer.
Spieler können verankerte Teile oder Modelle manipulieren, und sie bleiben genau dort, wo du sie bei der Freigabe platziert hast.
DragDetectors funktionieren im Studio, solange du die Werkzeuge Auswählen, Bewegen, Skalieren oder Drehen nicht verwendest, wodurch es einfacher ist, ziehbare Objekte während der Bearbeitung zu testen und anzupassen.
Objekte ziehbar machen
Um ein Teil oder Modell ziehbar zu machen, füge einfach einen DragDetector als direkten Nachfolger hinzu.
Wähle im Menü einen DragDetector ein.

Standardmäßig wird das Objekt jetzt im Bodenbereich ziehbar sein, aber du kannst seinen DragStyle anpassen, definieren, wie es auf Bewegungen reagiert und optional Achsen- oder Bewegungsgrenzen anwenden.
Zieherkennung anpassen
Ziehstil
DragDetectors ordnen die Cursorbewegung virtuellen Linien und Ebenen zu, um vorgeschlagene 3D-Bewegungen zu berechnen. Über die Eigenschaft DragStyle kannst du aus verschiedenen Zuordnungen wählen, die deinen Bedürfnissen entsprechen. Zum Beispiel erzeugt TranslatePlane eine Translation in einer virtuellen Ebene, während RotateAxis eine Rotation um eine virtuelle Achse erzeugt.
| Einstellung | Beschreibung |
|---|---|
| TranslateLine | 1D-Bewegung entlang der Achse des Detektors Axis, standardmäßig die Weltachse Y. |
| TranslatePlane | 2D-Bewegung in der Ebene, die senkrecht zur Achse des Detektors Axis steht, standardmäßig die Welt-Ebene XZ. |
| TranslatePlaneOrLine | 2D-Bewegung in der Ebene senkrecht zur Achse des Detektors Axis und, wenn der Modifier aktiv ist, 1D-Bewegung entlang der Achse des Detektors Axis. |
| TranslateLineOrPlane | 1D-Bewegung entlang der Achse des Detektors Axis und, wenn der Modifier aktiv ist, 2D-Bewegung in der Ebene senkrecht zur Achse des Detektors Axis. |
| TranslateViewPlane | 2D-Bewegung in der Ebene senkrecht zur Ansicht der Kamera. In diesem Modus wird die Ebene ständig aktualisiert, selbst während des Ziehens, und wird immer der aktuellen Ansicht der Kamera zugewandt. |
| RotateAxis | Rotation um die Achse des Detektors Axis, standardmäßig die Weltachse Y. |
| RotateTrackball | Trackball-Rotation, die weiter angepasst wird durch die Eigenschaften TrackballRadialPullFactor und TrackballRollFactor. |
| BestForDevice | TranslatePlaneOrLine für Maus und Gamepad; TranslatePlane für Touch; 6DOF für VR. |
| Scriptable | Berechnet die gewünschte Bewegung über eine benutzerdefinierte Funktion, die über SetDragStyleFunction() bereitgestellt wird. |
Ziehrichtung
Standardmäßig sind 3D-Bewegungen und die zugehörige DragStyle auf den Weltbereich abgebildet. Du möchtest möglicherweise die ReferenceInstance, Orientation oder Axis ändern, beispielsweise beim Erstellen von Zieherkennungen für Modelle mit verstellbaren Teilen.
| Eigenschaft | Beschreibung | Standard |
|---|---|---|
| ReferenceInstance | Eine Instanz, deren Pivot den Referenzrahmen für den Zieherkennung bereitstellt. Der DragFrame wird relativ zu diesem Referenzrahmen ausgedrückt, der über GetReferenceFrame() abgerufen werden kann. Wenn der Referenzrahmen nil ist, erfolgt die Translation in Richtung der Eigenschaft Axis im Weltbereich (oder in der Ebene senkrecht dazu). | nil |
| Orientation | Bestimmt die YXZ-Rotation der Bewegungsachsen relativ zum Referenzrahmen (ändert nicht die Ausrichtung des Referenzrahmens selbst). Lineare Translation und axiale Rotation finden auf dieser neu orientierten Y-Achse statt, und die planare Translation erfolgt in der XZ-Ebene. Eine Änderung dieses Wertes aktualisiert automatisch Axis und umgekehrt. | (0, 0, 0) |
| Axis | Die primäre Bewegungsachse, ausgedrückt relativ zum Referenzrahmen. Eine Änderung dieses Wertes aktualisiert automatisch Orientation und umgekehrt. | (0, 1, 0) |
Reaktion auf Bewegung
Die Eigenschaft ResponseStyle gibt an, wie ein Objekt auf die vorgeschlagene Bewegung reagiert, abhängig davon, ob das Objekt Anchored ist oder nicht.
| Einstellung | Angekettetes Verhalten | Unangekettetes Verhalten |
|---|---|---|
| Geometric | Sowohl innerhalb der laufenden Erfahrung als auch im Studio-Bearbeitungsmodus wird die Position/Ausrichtung eines angestellten Objekts genau aktualisiert, um die vorgeschlagene Bewegung widerzuspiegeln. | Für ein unangestelltes Objekt ist das Verhalten dasselbe wie bei einem angestellten Objekt. Jedoch wird in einer laufenden Erfahrung das Objekt zu Beginn des Ziehens angestellt und nach der Freigabe des Ziehens wieder unangestellt. |
| Physical | Ein angestelltes Objekt wird standardmäßig auf Geometric-Verhalten eingestellt, da es nicht von Kräften beeinflusst wird. | Ein unangestelltes Objekt wird durch Zwangskräfte bewegt, die versuchen, es in die gewünschte Position und/oder Ausrichtung zu bringen, die durch die vorgeschlagene Bewegung gegeben ist. |
| Custom | Das Objekt wird sich überhaupt nicht bewegen, aber DragFrame wird weiterhin aktualisiert und du kannst auf die Ziehmanipulation reagieren, wie du möchtest. | (gleich wie angestellt) |
Achsen- & Bewegungsgrenzen
Standardmäßig gibt es keine Grenzen für 3D-Bewegungen, außer den inhärenten Einschränkungen der DragStyle. Wenn notwendig, kannst du minimale und maximale Grenzen für sowohl Translation als auch Rotation anwenden. Beachte jedoch, dass dies keine Einschränkungen sind; sie behindern lediglich die Versuche des Zieherkennungs, Bewegungen zu generieren, um innerhalb der Grenzen zu bleiben.
| Eigenschaften | Beschreibung | Standard |
|---|---|---|
| Begrenzt die Ziehtranslation in jeder Dimension. Wenn MaxDragTranslation größer ist als MinDragTranslation, wird die Translation innerhalb dieses Bereichs eingeengt. | (0, 0, 0) | |
| Nur relevant, wenn DragStyle auf RotateAxis eingestellt ist. Wenn MaxDragAngle größer ist als MinDragAngle, wird die Rotation innerhalb dieses Bereichs eingeengt. | 0 |
Zieherlaubnisse
Die Erlaubnis von Spielern, mit einer bestimmten Instanz der Zieherkennung zu interagieren, kann über die Eigenschaft PermissionPolicy festgelegt werden. Dies ist standardmäßig auf Enum.DragDetectorPermissionPolicy.Everybody eingestellt und kann auch geändert werden, um scripted Berechtigungssteuerungen zu unterstützen, wie im Codebeispiel gezeigt.
| Einstellung | Beschreibung |
|---|---|
| Nobody | Keine Spieler können mit der DragDetector interagieren. |
| Everybody | Alle Spieler können mit der DragDetector interagieren. |
| Scriptable | Die Zieherlaubnisse der Spieler werden durch eine Funktion bestimmt, die über SetPermissionPolicyFunction() registriert ist. Unter dieser Einstellung wird die Registrierung einer Funktion oder die Rückgabe eines ungültigen Ergebnisses alle Spieler am Ziehen hindern. |
DragDetector - Scripted Drag Permission
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)
Physikalische Reaktion
Vorausgesetzt, der Reaktionsstil eines Ziehers ist auf Physical eingestellt und wird auf ein unangestelltes Objekt angewendet, wird dieses Objekt durch Zwangskräfte bewegt, die versuchen, es in die Position/Ausrichtung zu bringen, die durch die vorgeschlagene Bewegung gegeben ist. Du kannst die physikalische Antwort weiter anpassen durch die folgenden Eigenschaften:
| Eigenschaft | Beschreibung | Standard |
|---|---|---|
| ApplyAtCenterOfMass | Wenn falsch, wird die Ziehkraft an dem Punkt angewendet, auf den der Benutzer klickt. Wenn wahr, wird die Kraft am Schwerpunkt des Objekts angewendet. | false |
| MaxForce | Maximale Kraft, die angewendet wird, damit das Objekt sein Ziel erreicht. | 10000000 |
| MaxTorque | Maximales Drehmoment, das angewendet wird, damit das Objekt sein Ziel erreicht. | 10000 |
| Responsiveness | Höhere Werte führen dazu, dass das Objekt schneller sein Ziel erreicht. | 10 |
Modifier-Eingabe
Einige DragStyle-Modi erlauben es Benutzern, eine Modifier-Taste/-Taste gedrückt zu halten, um das gezogene Objekt auf verschiedene Weise zu manipulieren. Standardmäßig ist der Modifier auf LeftControl auf PC, ButtonR1 auf Gamepad oder ButtonL2 auf VR. Du kannst diese Modifier durch die Eigenschaften KeyboardModeSwitchKeyCode, GamepadModeSwitchKeyCode oder VRSwitchKeyCode der Instanz der Zieherkennung anpassen.
Replikation
Wenn die Eigenschaft RunLocally falsch (Standard) ist, interpretiert der Client alle Eingaben, um Daten zu erzeugen, die er an den Server sendet, um das Ziehen durchzuführen. In diesem Modus müssen alle benutzerdefinierten Ereignissignale und registrierten Funktionen im Server Scripts sein.
Wenn die Eigenschaft RunLocally wahr ist, werden keine Ereignisse an den Server repliziert. Alle benutzerdefinierten Ereignissignale und registrierten Funktionen müssen im Client LocalScripts sein und du musst Remote-Events verwenden, um notwendige Änderungen an den Server zu übertragen.
Skriptreaktionen auf Klicken und Ziehen
Durch Ereignissignale, Eigentumsänderungen, Scriptable Ziehstil und benutzerdefinierte Funktionen können Skripte auf die Manipulation gezogener Objekte reagieren, um die Benutzeroberfläche zu steuern oder logische Entscheidungen zu treffen, beispielsweise um das Lichtniveau in einem Raum basierend auf einem schiebenden Wandschalterdimmer anzupassen.
Ereignissignale
Durch die folgenden Ereignissignale kannst du erkennen, wann ein Benutzer mit dem Ziehen eines Objekts beginnt, fortfährt und aufhört.
| Ereignis | Beschreibung |
|---|---|
| DragStart | Ausgelöst, wenn ein Benutzer mit dem Ziehen des Objekts beginnt. |
| DragContinue | Ausgelöst, wenn ein Benutzer das Ziehen des Objekts fortsetzt, nachdem DragStart initiiert wurde. |
| DragEnd | Ausgelöst, wenn ein Benutzer aufhört, das Objekt zu ziehen. |
DragDetector - Ereignissignale
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)
Änderungen des Ziehrrahmens
Zusätzlich zu Ereignissignalen kannst du Änderungen am DragFrame des Detektors direkt überwachen.
DragDetector - DragFrame Änderungen
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)
Scripted Ziehstil
Wenn du den DragStyle eines Detektors auf Scriptable einstellst, kannst du deine eigene Funktion bereitstellen, die einen Ray annimmt und eine Weltkoordinate CFrame zurückgibt. Der Detektor wird die Bewegung so anpassen, dass das gezogene Objekt dorthin gelangt.
DragDetector - Scripted DragStyle
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)
-- Exclude dragged object from raycast detection
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)
Benutzerdefinierte Einschränkungsfunktion
Zieherkennung hat keine eingebauten Bewegungsregeln für Raster und Schnappen, aber du kannst benutzerdefinierte Einschränkungsfunktionen registrieren, um das DragFrame des Detektors zu bearbeiten, bevor es angewendet wird. Zum Beispiel kannst du die Bewegung auf einem Raster halten, indem du Positionen auf Vielfache des Rasterincremente rundest oder ein Schachspiel mit erlaubten Bewegungsregeln für jede Figur simulieren.
DragDetector - Benutzerdefinierte Einschränkungsfunktion
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)
-- When applicable, remove the constraint function by invoking connection:Disconnect()
Beispielverwendung
Unangestellte physikalische Objekte
Eine grundlegende Implementierung der Zieherkennung ist ein Turmbalance-Spiel, bei dem die Spieler vorsichtig Teile entfernen müssen und versuchen, den Turm aufrecht zu halten. In der folgenden Turmstruktur hat jedes Teil einen untergeordneten DragDetector mit dem Standard DragStyle von TranslatePlane, sodass die Spieler die Teile nach außen ziehen, jedoch nicht nach oben oder unten.
Angekettete Modelle mit verstellbaren Teilen
Du kannst leicht Modelle erstellen und teilen, die hauptsächlich angestellt sind, aber eines oder mehrere untergeordnete Teile/Modelle haben, die Spieler ziehen können. Zum Beispiel hat der folgende Schreibtisch zwei Schubladen, die die Spieler öffnen können, um zu inspizieren, was darin ist.
Zieherkennung und Einschränkungen
Du kannst Zieherkennung mit Constraints kombinieren, zum Beispiel bei einer Marionettenpuppe. In der folgenden Konfiguration sind die Steuergriffe verankert, die Körperteile sind unangekettet, und Einschränkungen halten die Marionette zusammen. Das Bewegen der Griffe mit dem TranslateViewPlane DragStyle lässt die Marionette tanzen, und die einzelnen Körperteile können ebenfalls mit Zieherkennung bewegt werden, während das Modell seine Integrität behält.
3D-Benutzerschnittstellen
3D-Benutzerschnittstellen sind leicht durch Zieherkennung erreichbar, wie das Anpassen der Helligkeit eines SpotLight basierend auf einem schiebenden Schalterdimmer. Du kannst auch die X- und Z-Achsen einzeln erkennen, um zwei verschiedene Aspekte einer 3D-Benutzerschnittstelle zu steuern, beispielsweise die Size, Speed und Color eines ParticleEmitter.
DragDetector - 3D-Benutzerschnittstelle
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
-- Passen Sie die Partikelgröße und -geschwindigkeit basierend auf dem X-Faktor des Ziehdetektors an
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)
-- Passen Sie die Partikelfarbe basierend auf dem Z-Faktor des Ziehdetektors an
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)