UIDragDetector 实例促进并鼓励与游戏中的 2D 用户界面元素(如滑块、旋转器等)的交互。主要功能包括:
在任何 GuiObject 实例下放置一个 UIDragDetector,使其可以通过所有用户输入进行拖动,而无需编写一行代码。
从多个 DragStyle 选项中选择,定义对象如何响应运动,通过 ResponseStyle,并可选择应用轴、运动限制或拖动边界。
脚本可以响应被拖动对象的操作,以驱动逻辑响应,例如调整设置。
UIDragDetectors 在 Studio 的编辑和播放模式下工作,只要您不使用 选择、移动、缩放或 旋转 工具,以及某些插件或 Studio 的 UI 编辑器工具。
使 UI 元素可拖动
要使任何 GuiObject 实例可拖动,只需将 UIDragDetector 作为直接子项添加。
从菜单中插入 UIDragDetector。

默认情况下,该对象现在将在 LayerCollector 界面中可拖动。
自定义 UI 拖动检测器
拖动样式
UIDragDetectors 将光标运动映射到计算建议的 2D 运动和/或旋转。通过 DragStyle 属性,您可以选择不同的映射以满足您的需求。例如,Enum.UIDragDetectorDragStyle.TranslatePlane 在 LayerCollector 的 2D 平面中产生平移,而 Enum.UIDragDetectorDragStyle.Rotate 通常产生旋转而不是平移。
| 设置 | 描述 |
|---|---|
| TranslateLine | 沿检测器的 DragAxis 的 1D 运动。 |
| TranslatePlane | 在 LayerCollector 的平面中的 2D 运动。 |
| Rotate | 默认情况下,围绕检测器父级 GuiObject 的绝对中心位置旋转。如果设置了 ReferenceUIInstance,则围绕该实例的绝对中心位置旋转。 |
| Scriptable | 通过 SetDragStyleFunction() 提供的自定义函数计算所需的运动。 |
拖动方向
默认情况下,2D 运动和相关的 DragStyle 映射到祖先 LayerCollector 的空间。然而,您可能希望在构建不同的 UI 组件时更改 ReferenceUIInstance 或 DragAxis。
| 设置 | 描述 | 默认 |
|---|---|---|
| ReferenceUIInstance | 一个 GuiObject 实例,其局部空间和绝对中心位置是检测器的参考空间和原点。设置此参考会影响 DragUDim2、DragRotation 和 DragAxis 的行为等属性。 | nil |
| DragAxis | Vector2 值,定义当 DragStyle 设置为 Enum.UIDragDetectorDragStyle.TranslateLine 时被拖动对象的运动轴。该轴在 UIDragDetector 的局部空间中定义,除非定义了 ReferenceUIInstance,在这种情况下,该轴在该实例的局部空间中定义。 | (1, 0) |
对运动的响应
UIDragDetector.ResponseStyle 属性指定对象的位置值如何通过建议的运动进行更改。自定义响应样式允许您根据需要使用结果的 UIDragDetector.DragUDim2 和 UIDragDetector.DragRotation 值,而无需检测器的父级执行建议的运动。
| 设置 | 描述 |
|---|---|
| Offset | 根据检测器父级的 GuiObject.Position 值的 Offset 值移动。这是默认设置。 |
| Scale | 根据检测器父级的 GuiObject.Position 值的 Scale 值移动。 |
| CustomOffset | UI 元素将完全不移动,但检测器的 DragUDim2 的 Offset 值仍将被更新,检测器的事件仍将触发,允许您根据需要响应拖动操作。 |
| CustomScale | UI 元素将完全不移动,但检测器的 DragUDim2 的 Scale 值仍将被更新,检测器的事件仍将触发,允许您根据需要响应拖动操作。 |
平移和旋转限制
默认情况下,2D 运动没有限制,除了 DragStyle 的固有限制。如果需要,可以通过以下属性声明最小和最大平移和旋转的限制。此外,您可以定义被拖动对象在指定的 GuiObject(例如 Frame)的边界内如何约束。
| 属性 | 描述 | 默认 |
|---|---|---|
| MinDragTranslation MaxDragTranslation | 在每个维度上的拖动平移限制,由 UDim2 值定义。如果 MaxDragTranslation 大于 MinDragTranslation,则平移将在该范围内被限制。 | {0, 0}, {0, 0} |
| MinDragAngle MaxDragAngle | 仅在 DragStyle 设置为 Enum.UIDragDetectorDragStyle.Rotate 时相关,或者如果通过 SetDragStyleFunction() 或 AddConstraintFunction() 设置的函数定义了旋转值。如果 MaxDragAngle 大于 MinDragAngle,则旋转将在该范围内被限制。 | 0 |
| BoundingBehavior | 确定 UIDragDetector 实例的边界行为,当其 BoundingUI 被设置时。将其设置为 EntireObject 会将整个拖动的 UI 限制在 BoundingUI 内,而将其设置为 HitPoint 仅根据确切的命中/抓取点及其在平移/旋转后的相应位置限制拖动的 UI。作为便利,Automatic 的默认值模拟了对于完全包含在 BoundingUI 内的 UI 对象的 EntireObject 行为,或者对于部分在 BoundingUI 外部的 UI 对象的 HitPoint 行为。 | Automatic |
速度调整
通过 SelectionModeDragSpeed 和 SelectionModeRotateSpeed,您可以微调检测器的最大拖动/旋转速度。此外,通过 UIDragSpeedAxisMapping,您可以根据检测器的 SelectionModeDragSpeed 微调 X/Y 维度的拖动速度。
| 属性 | 描述 |
|---|---|
| SelectionModeDragSpeed | 定义平移的最大拖动速度,作为 Scale 和 Offset 的组合,适用于检测器所属的第一个祖先 ScreenGui 或 SurfaceGui。 |
| SelectionModeRotateSpeed | 定义 UIDragDetector 可以旋转的最大角度每秒。 |
| UIDragSpeedAxisMapping | 根据检测器的 SelectionModeDragSpeed 确定 X/Y 维度的拖动速度。默认值为 XY,意味着 X 和 Y 轴的速度分别基于 X 和 Y 的 Scale/Offset 值。 替代方案为 XX 和 YY,意味着 X 和 Y 轴的速度分别基于 X (XX) 或 Y (YY) 轴的 Scale,而 Offset 值仍适用于各自的轴。例如,如果第一个祖先 ScreenGui 的大小为 800×600,且 SelectionModeDragSpeed 为 {0.1, 10}, {0.1, 20},则设置为 XX 将导致 X/Y 拖动速度为 80+10/80+20,而 YY 将导致 60+10/60+20(注意 Offset 值在两种情况下保持不变)。 |
脚本对点击和拖动的响应
通过 事件信号、属性更改、Scriptable 拖动样式和自定义函数,脚本可以响应被拖动 UI 元素的操作,以驱动各种设置或做出逻辑决策,例如调整音乐和音效音量的滑块。
事件信号
通过以下事件信号,您可以检测用户何时开始、继续和结束拖动对象。
| 事件 | 描述 |
|---|---|
| DragStart | 当用户开始拖动对象时触发。 |
| DragContinue | 当用户在 DragStart 被触发后继续拖动对象时触发。 |
| DragEnd | 当用户停止拖动对象时触发。 |
以下滑块将其容器指定为 BoundingUI,以限制其在容器区域内的移动,允许基于比例的 TranslateLine 拖动限制在容器的整个宽度内,而无需额外的脚本。
-- 层级为 SliderContainer ⟩ Handle ⟩ UIDragDetector ⟩ (此脚本)
local sliderContainer = script.Parent.Parent.Parent
local handle = sliderContainer:FindFirstChild("Handle")
local uiDragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
uiDragDetector.ResponseStyle = Enum.UIDragDetectorResponseStyle.Scale -- 设置按比例拖动
uiDragDetector.DragStyle = Enum.UIDragDetectorDragStyle.TranslateLine -- 限制拖动为线性
uiDragDetector.BoundingUI = sliderContainer
-- 初始设置容器透明度为手柄的 X 比例值
sliderContainer.BackgroundTransparency = 1 - handle.Position.X.Scale
-- 扩大手柄边框以指示抓取开始
uiDragDetector.DragStart:Connect(function(inputPosition)
handle:FindFirstChildWhichIsA("UIStroke").Thickness = 6
end)
-- 根据拖动的比例变化透明度
uiDragDetector.DragContinue:Connect(function(inputPosition)
sliderContainer.BackgroundTransparency = 1 - handle.Position.X.Scale
end)
-- 恢复手柄边框以指示抓取结束
uiDragDetector.DragEnd:Connect(function(inputPosition)
handle:FindFirstChildWhichIsA("UIStroke").Thickness = 4
end)位置和旋转变化
除了 事件信号 之外,您还可以直接监控检测器的 DragUDim2 和/或 DragRotation 属性的变化。
以下检测器的 DragStyle 设置为 Rotate,允许用户在色调旋转环上拖动手柄,同时通过 Instance:GetPropertyChangedSignal() 检测拖动旋转的变化。
local handle = script.Parent.Parent -- 要拖动的 UI 元素
local uiDragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
uiDragDetector.DragStyle = Enum.UIDragDetectorDragStyle.Rotate -- 设置拖动样式为旋转
local function changeHue()
local currAngle = (math.fmod(handle.Rotation, 360)) / 360
if currAngle < 0 then
currAngle += 1
end
handle.BackgroundColor3 = Color3.fromHSV(currAngle, 1, 1)
end
-- 初始设置色调为手柄旋转
changeHue()
-- 将函数连接到检测器的拖动旋转的 GetPropertyChangedSignal()
uiDragDetector:GetPropertyChangedSignal("DragRotation"):Connect(changeHue)脚本化拖动样式
如果您将检测器的 UIDragDetector.DragStyle 设置为 Enum.UIDragDetectorDragStyle.Scriptable,您可以提供自己的函数,该函数接受一个 Vector2 的输入位置并返回一个 UDim2(位置)和一个浮点数(旋转)。检测器将根据返回值、DragSpace 属性和 DragRelativity 属性更新对象到计算的位置/旋转。
默认情况下,返回的 UDim2 和浮点数将是检测器父级的局部空间中的 最终 所需位置/旋转。现有的平移/旋转限制仍将适用,以及由指定的 BoundingUI 实例施加的边界限制。
以下示例根据 X 坐标输入的变化拖动 UI 元素,遵循计算出的正弦波。请注意,检测器的 DragSpace 设置为 Enum.UIDragDetectorDragSpace.Relative。
local frame = script.Parent -- 要拖动的 UI 元素
local uiDragDetector = frame:FindFirstChildWhichIsA("UIDragDetector")
local initialXValue = 0
local maxHeightChange = 200
local pixelsPerRadian = 75 -- 降低此值以增加频率
uiDragDetector.DragStart:Connect(function(inputPosition)
initialXValue = inputPosition.X
end)
local function computeSinWaveCoordinate(inputPosition)
local deltaX = inputPosition.X - initialXValue
-- 负 Y delta 使其在屏幕上随着正 Y 变化而“向上”移动
local deltaY = -math.sin(deltaX / pixelsPerRadian) * maxHeightChange
return UDim2.fromOffset(deltaX, deltaY)
end
uiDragDetector:SetDragStyleFunction(computeSinWaveCoordinate)自定义约束函数
UIDragDetectors 没有关于网格和对齐的内置运动规则,但您可以注册自定义约束函数,以在应用之前编辑检测器的 UIDragDetector.DragUDim2 和 UIDragDetector.DragRotation。例如,您可以通过将位置四舍五入到特定增量来保持运动在网格上,或定义允许的运动区域。请注意,这在任何现有的平移/旋转限制之前应用。
以下示例利用约束函数将平面拖动限制在基于行和列数量的 X/Y 网格中。请注意,检测器的 ResponseStyle 设置为 Enum.UIDragDetectorResponseStyle.Scale,其 BoundingUI 设置为网格容器。
-- 层级为 GridContainer ⟩ Handle ⟩ UIDragDetector ⟩ (此脚本)
local gridContainer = script.Parent.Parent.Parent
local handle = gridContainer:FindFirstChild("Handle") -- 要拖动的 UI 元素
local uiDragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
uiDragDetector.ResponseStyle = Enum.UIDragDetectorResponseStyle.Scale -- 设置按比例拖动
uiDragDetector.DragRelativity = Enum.UIDragDetectorDragRelativity.Relative
uiDragDetector.BoundingUI = gridContainer
local NUM_COLUMNS = 10
local NUM_ROWS = 5
local xScaleIncrement = 1 / NUM_COLUMNS
local yScaleIncrement = 1 / NUM_ROWS
local initialParentPosition = uiDragDetector.Parent.Position
uiDragDetector.DragStart:Connect(function()
initialParentPosition = uiDragDetector.Parent.Position
end)
local function dragToGridOnly(proposedPosition, proposedRotation)
local griddedXScale = math.round(proposedPosition.X.Scale / xScaleIncrement) * xScaleIncrement
local griddedYScale = math.round(proposedPosition.Y.Scale / yScaleIncrement) * yScaleIncrement
return UDim2.fromScale(griddedXScale, griddedYScale), proposedRotation
end
uiDragDetector:AddConstraintFunction(1, dragToGridOnly)