Roblox GUI Maker
← 全部教程

交互

如何制作可拖拽的 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。