L'instance DragDetector facilite et encourage l'interaction avec des objets 3D dans une expérience, tels que l'ouverture de portes et de tiroirs, le déplacement d'une pièce, la prise et le lancer d'une boule de bowling, le tir avec une fronde, et bien plus encore. Les caractéristiques principales incluent :
Placez un DragDetector sous n'importe quel BasePart ou Model pour le rendre glissable via toutes les entrées (souris, tactile, manette et VR), le tout sans une seule ligne de code.
Choisissez parmi plusieurs styles de glissement, définissez comment l'objet réagit au mouvement et appliquez éventuellement des limites d'axe ou de mouvement.
Les scripts peuvent réagir à la manipulation des objets glissés pour faire fonctionner l'UI ou prendre des décisions logiques, comme ajuster le niveau de lumière dans une pièce en fonction d'un variateur de lumière à bascule.
Les joueurs peuvent manipuler des pièces ou des modèles ancrés et ils resteront exactement où vous les avez placés lors de la libération.
DragDetectors fonctionnent dans Studio tant que vous n'utilisez pas les outils Sélectionner, Déplacer, Échelle ou Faire tourner, ce qui facilite le test et l'ajustement des objets glissables pendant l'édition.
Rendre les objets glissables
Pour rendre n'importe quelle pièce ou modèle glissable, il suffit d'ajouter un DragDetector comme descendant direct.
Dans la fenêtre Explorateur, survolez le Part, MeshPart, ou Model et cliquez sur le bouton ⊕. Un menu contextuel s'affiche.
Dans le menu, insérez un DragDetector.

Par défaut, l'objet sera désormais glissable dans le plan au sol, mais vous pouvez personnaliser son DragStyle, définir comment il réagit au mouvement, et appliquer éventuellement des limites d'axe ou de mouvement.
Personnaliser les détecteurs de glissement
Style de glissement
DragDetectors associent le mouvement du curseur à des lignes et des plans virtuels pour calculer le mouvement 3D proposé. Grâce à la propriété DragStyle, vous pouvez choisir parmi différents mappages pour répondre à vos besoins. Par exemple, TranslatePlane produit une translation dans un plan virtuel, tandis que RotateAxis produit une rotation autour d'un axe virtuel.
| Paramètre | Description |
|---|---|
| TranslateLine | Mouvement 1D le long de l'Axis du détecteur, par défaut l'axe Y du monde. |
| TranslatePlane | Mouvement 2D dans le plan perpendiculaire à l'Axis du détecteur, par défaut le plan XZ du monde. |
| TranslatePlaneOrLine | Mouvement 2D dans le plan perpendiculaire à l'Axis du détecteur et, lorsque le modificateur est actif, mouvement 1D le long de l'Axis du détecteur. |
| TranslateLineOrPlane | Mouvement 1D le long de l'Axis du détecteur et, lorsque le modificateur est actif, mouvement 2D dans le plan perpendiculaire à l'Axis du détecteur. |
| TranslateViewPlane | Mouvement 2D dans le plan perpendiculaire à la vue de la caméra. Dans ce mode, le plan est constamment mis à jour, même pendant le glissement, et fera toujours face à la vue actuelle de la caméra. |
| RotateAxis | Rotation autour de l'Axis du détecteur, par défaut l'axe Y du monde. |
| RotateTrackball | Rotation trackball, davantage personnalisée via les propriétés TrackballRadialPullFactor et TrackballRollFactor. |
| BestForDevice | TranslatePlaneOrLine pour souris et manette; TranslatePlane pour tactile; 6DOF pour VR. |
| Scriptable | Calcule le mouvement souhaité via une fonction personnalisée fournie via SetDragStyleFunction(). |
Direction de glissement
Par défaut, le mouvement 3D et le DragStyle associé sont mappés à l'espace mondial. Cependant, vous pourriez vouloir changer l'ReferenceInstance, l'Orientation, ou l'Axis, par exemple lors de la création de détecteurs de glissement dans des modèles avec des pièces réglables.
| Propriété | Description | Par défaut |
|---|---|---|
| ReferenceInstance | Une instance dont le pivot fournit le système de référence pour le détecteur de glissement. Le DragFrame est exprimé par rapport à ce système de référence qui peut être récupéré via GetReferenceFrame(). Si le système de référence est nil, la translation se fera dans la direction de (ou dans le plan perpendiculaire à) la propriété Axis dans l'espace mondial. | nil |
| Orientation | Spécifie la rotation YXZ des axes de mouvement par rapport au système de référence (ne change pas l'orientation du système de référence lui-même). La translation linéaire et la rotation axiale se feront sur cet axe Y réorienté, et la translation dans le plan XZ. Changer cette valeur met automatiquement à jour Axis et vice versa. | (0, 0, 0) |
| Axis | L'axe principal de mouvement, exprimé par rapport au système de référence. Changer cette valeur met automatiquement à jour Orientation et vice versa. | (0, 1, 0) |
Réponse au mouvement
La propriété ResponseStyle spécifie comment un objet répond au mouvement proposé, selon que l'objet est Anchored ou non.
| Paramètre | Comportement ancré | Comportement non ancré |
|---|---|---|
| Geometric | Tant à l'intérieur de l'expérience en cours qu'en mode d'édition Studio, la position/l'orientation d'un objet ancré sera mise à jour pour refléter exactement le mouvement proposé. | Pour un objet non ancré, le comportement est le même que pour un objet ancré. Cependant, dans une expérience en cours, l'objet sera ancré au début du glissement et rétabli comme non ancré à la libération du glissement. |
| Physical | Un objet ancré adoptera par défaut un comportement Géométrique, car il n'est pas affecté par des forces. | Un objet non ancré sera déplacé par des forces de contrainte qui tentent de le ramener à la position et/ou orientation souhaitée données par le mouvement proposé. |
| Custom | L'objet ne bougera pas du tout, mais le DragFrame sera toujours mis à jour et vous pouvez réagir à la manipulation du glissement comme vous le souhaitez. | (même que pour l'ancré) |
Limites d'axe et de mouvement
Par défaut, il n'y a pas de limites au mouvement 3D au-delà des restrictions inhérentes au DragStyle. Si nécessaire, vous pouvez appliquer des limites minimales et maximales à la fois pour la translation et la rotation. Notez cependant que ce ne sont pas des contraintes ; elles empêchent simplement le détecteur de glissement d'essayer de générer un mouvement afin de rester dans les limites.
| Propriétés | Description | Par défaut |
|---|---|---|
| Limites à la translation de glissement dans chaque dimension. Si MaxDragTranslation est supérieur à MinDragTranslation, la translation sera limitée dans cette plage. | (0, 0, 0) | |
| Uniquement pertinent si DragStyle est réglé sur RotateAxis. Si MaxDragAngle est supérieur à MinDragAngle, la rotation sera limitée dans cette plage. | 0 |
Autorisations de glissement
La permission des joueurs d'interagir avec une instance de détecteur de glissement donnée peut être spécifiée par la propriété PermissionPolicy. Celle-ci est définie par défaut sur Enum.DragDetectorPermissionPolicy.Everybody, et elle peut également être modifiée pour supporter des contrôles de permission scriptés comme indiqué dans l'exemple de code.
| Paramètre | Description |
|---|---|
| Nobody | Aucun joueur ne peut interagir avec le DragDetector. |
| Everybody | Tous les joueurs peuvent interagir avec le DragDetector. |
| Scriptable | Les permissions de glissement des joueurs seront déterminées par une fonction enregistrée via SetPermissionPolicyFunction(). Dans ce paramètre, le défaut d'enregistrement d'une fonction ou le retour d'un résultat invalide empêchera tous les joueurs de glisser. |
DragDetector - Autorisation de glissement scriptée
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)
Réponse physique
À supposer qu'un style de réponse de glissement réponse style soit défini sur Physique et qu'il soit appliqué à un objet non ancré, cet objet sera déplacé par des forces de contrainte qui tentent de le ramener à la position/orientation données par le mouvement proposé. Vous pouvez personnaliser davantage la réponse physique via les propriétés suivantes :
| Propriété | Description | Par défaut |
|---|---|---|
| ApplyAtCenterOfMass | Lorsque faux, la force de glissement s'applique au point sur lequel l'utilisateur clique. Lorsque vrai, la force s'applique au centre de masse de l'objet. | false |
| MaxForce | Force maximale appliquée pour que l'objet atteigne son objectif. | 10000000 |
| MaxTorque | Couple maximum appliqué pour que l'objet atteigne son objectif. | 10000 |
| Responsiveness | Des valeurs plus élevées font que l'objet atteint son objectif plus rapidement. | 10 |
Entrée modificateur
Certains modes de DragStyle permettent aux utilisateurs de maintenir une touche/bouton modifiable pour manipuler l'objet glissé de différentes manières. Par défaut, le modificateur est LeftControl sur PC, ButtonR1 sur manette, ou ButtonL2 sur VR. Vous pouvez personnaliser ces modificateurs via les propriétés KeyboardModeSwitchKeyCode, GamepadModeSwitchKeyCode, ou VRSwitchKeyCode de l'instance de détecteur de glissement.
Réplication
Lorsque la propriété RunLocally est fausse (par défaut), le client interprète toutes les entrées pour produire des données qu'il envoie au serveur pour effectuer le glissement. Dans ce mode, tous les signaux d'événements personnalisés et fonctions enregistrées doivent se trouver dans Scripts du serveur.
Lorsque la propriété RunLocally est vraie, aucun événement n'est répliqué sur le serveur. Tous les signaux d'événements personnalisés et fonctions enregistrées doivent se trouver dans LocalScripts du client et vous devez utiliser des événements distants pour propager les changements nécessaires au serveur.
Réponses de script au clic et au glissement
À travers les signaux d'événements, les changements de propriété, le style de glissement Scriptable, et les fonctions personnalisées, les scripts peuvent répondre à la manipulation des objets glissés pour faire fonctionner l'UI ou prendre des décisions logiques, telles qu'ajuster le niveau de lumière dans une pièce en fonction d'un variateur de lumière à bascule.
Signaux d'événements
À travers les signaux d'événements suivants, vous pouvez détecter quand un utilisateur commence, continue et termine de glisser un objet.
| Événement | Description |
|---|---|
| DragStart | Se déclenche lorsqu'un utilisateur commence à glisser l'objet. |
| DragContinue | Se déclenche lorsqu'un utilisateur continue de glisser l'objet après que DragStart a été initié. |
| DragEnd | Se déclenche lorsqu'un utilisateur cesse de glisser l'objet. |
DragDetector - Signaux d'événements
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)
Changements du cadre de glissement
En plus des signaux d'événements, vous pouvez surveiller les changements à DragFrame du détecteur directement.
DragDetector - Changements de DragFrame
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)
Style de glissement scripté
Si vous définissez le DragStyle d'un détecteur sur Scriptable, vous pouvez fournir votre propre fonction qui prend un Ray et retourne un CFrame dans l'espace mondial. Le détecteur déplacera le mouvement de manière à ce que l'objet glissé aille à cet emplacement/orientation personnalisés.
DragDetector - DragStyle scripté
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)
-- Exclure l'objet glissé de la détection 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)
Fonction de contrainte personnalisée
Les détecteurs de glissement n'ont pas de règles de mouvement intégrées concernant les grilles et l'accrochage, mais vous pouvez enregistrer des fonctions de contrainte personnalisées pour modifier le DragFrame du détecteur avant qu'il ne soit appliqué. Par exemple, vous pouvez maintenir le mouvement sur une grille en arrondissant les positions aux multiples de l'incrément de la grille, ou simuler un jeu d'échecs avec des règles de mouvement légales pour chaque pièce.
DragDetector - Fonction de contrainte personnalisée
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)
-- Le cas échéant, supprimez la fonction de contrainte en invoquant connection:Disconnect()
Exemple d'utilisation
Objets physiques non ancrés
Une mise en œuvre de base des détecteurs de glissement est un jeu d'équilibre de tour où les joueurs doivent retirer des pièces avec précaution et tenter de maintenir la tour droite. Dans la structure de tour suivante, chaque pièce a un enfant DragDetector avec un DragStyle par défaut de TranslatePlane afin que les joueurs puissent tirer les pièces vers l'extérieur mais pas vers le haut ou vers le bas.
Modèles ancrés avec des pièces réglables
Vous pouvez facilement créer et partager des modèles qui sont principalement ancrés, mais qui ont une ou plusieurs pièces/modèles enfants que les joueurs peuvent glisser. Par exemple, le bureau suivant a deux tiroirs que les joueurs peuvent ouvrir pour inspecter ce qu'il y a à l'intérieur.
Détecteurs de glissement et contraintes
Vous pouvez combiner des détecteurs de glissement avec des Constraints, par exemple une marionnette. Dans la configuration suivante, les poignées de contrôle sont ancrées, les parties du corps sont non ancrées, et des contraintes maintiennent la marionnette ensemble. Déplacer les poignées avec le style de glissement DragStyle TranslateViewPlane fait danser la marionnette, et les différentes parties du corps peuvent également être déplacées avec des détecteurs de glissement, tout en maintenant l'intégrité du modèle.
Interfaces utilisateur 3D
Les interfaces utilisateur 3D sont facilement réalisables grâce aux détecteurs de glissement, comme ajuster la luminosité d'une SpotLight en fonction d'un variateur à bascule. Vous pouvez également détecter les axes X et Z individuellement pour contrôler deux aspects différents d'une interface utilisateur 3D, tels que la Size, Speed, et Color d'un ParticleEmitter.
DragDetector - Interface utilisateur 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
-- Ajuster la taille et la vitesse des particules en fonction du facteur X du détecteur de glissement
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)
-- Ajuster la couleur des particules en fonction du facteur Z du détecteur de glissement
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)