← 全部教程
交互
如何制作可拖拽的 Roblox GUI
一个可拖拽的窗口、背包或设置面板用起来很原生。诀窍在 UserInputService:按下开始拖、InputChanged 时移动 Frame、松开停止。关键细节是在开始时记录光标和 Frame 之间的偏移,这样它不会一下子吸到角落。
1. 追踪按下、移动和松开
在标题栏(不是整个面板)上监听,这样里面的按钮还能用。InputBegan 开始拖;UserInputService.InputChanged 移动它;InputEnded 停止。
local UserInputService = game:GetService("UserInputService")
local dragging, dragStart, startPos
titleBar.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
or input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragStart = input.Position
startPos = frame.Position
end
end)2. 让 Frame 跟着光标移动
在 InputChanged 里,把光标自 dragStart 以来的位移加到 Frame 的起始位置上。在 UDim2.new 里混合 Scale 和 Offset,无论 Frame 原本怎么定位都能正常工作。
UserInputService.InputChanged:Connect(function(input)
if not dragging then return end
if input.UserInputType == Enum.UserInputType.MouseMovement
or input.UserInputType == Enum.UserInputType.Touch then
local delta = input.Position - dragStart
frame.Position = UDim2.new(
startPos.X.Scale, startPos.X.Offset + delta.X,
startPos.Y.Scale, startPos.Y.Offset + delta.Y
)
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
or input.UserInputType == Enum.UserInputType.Touch then
dragging = false
end
end)提示: 用一个标题栏 Frame 来拖动,而不是整个面板 —— 否则拖动会吞掉里面按钮的点击。
常见问题
为什么抓取时 Frame 会跳到光标位置?
你把 Position 直接设成了光标位置。正确做法是在拖动开始时记录 startPos = frame.Position,再把光标的位移(delta)加到它上面,这样 Frame 保留它的抓取点。
这在手机上能用吗?
能 —— 在 InputBegan 和 InputEnded 里把 Enum.UserInputType.Touch 当成 MouseButton1 一样处理,在 InputChanged 里处理 Touch。
