Help with ui dragging

so im trying to make a inventory/hotbar system where ur able to drag stuff from your inventory, then put them on ur hotbar and vise versa, also able to switch arround the items in the players hotbar. i have an iossue with the dragging system, first issue is that whenever i try to drag the ui the ui appears further away from my mouse:


second issue is in relaiton to the isoverlaping function, it brings the error:

which is odd because im not refrensing the ui gridlayout but rather the temp frame i made.

inventory help.rbxl (74.1 KB)

local runservice = game:GetService("RunService")
local plr = game:GetService("Players").LocalPlayer
local inventoryGui = plr.PlayerGui.Inventory
local scrollingframe = inventoryGui.Inventory.ScrollingFrame
local hotbarframe = inventoryGui.HotBarFrame

local Drag = script.Parent
gsCoreGui = game:GetService("CoreGui")
gsTween = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")



function IsOverlapping(f1,f2)
	local f1pos,f2pos,f1size,f2size = f1.AbsolutePosition,f2.AbsolutePosition,f1.AbsoluteSize,f2.AbsoluteSize
	local xoverlap = (f1pos.x <= f2pos.x and f2pos.x < f1pos.x + f1size.x)
	local yoverlap = (f1pos.y <= f2pos.y and f2pos.y < f1pos.y - f1size.y)
	return xoverlap or yoverlap
end

local dragging
local dragInput
local dragStart
local startPos

local function update(input)
	local delta = input.Position - dragStart
	local dragTime = 0.04
	local SmoothDrag = {}
	SmoothDrag.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
	local dragSmoothFunction = gsTween:Create(Drag, TweenInfo.new(dragTime, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), SmoothDrag)
	dragSmoothFunction:Play()
end

Drag.InputBegan:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		Drag.Parent = inventoryGui
		dragging = true
		dragStart = input.Position
		startPos = Drag.Position
		input.Changed:Connect(function()
			if input.UserInputState == Enum.UserInputState.End then
				if IsOverlapping(Drag, scrollingframe) then
					Drag.Parent = scrollingframe
				else
					for i,v in hotbarframe:GetChildren() do
						if IsOverlapping(Drag,v) then
							Drag.Position = v.Position
							return
						end
					end
					
					Drag.Parent = scrollingframe
					
				end
			end
		end)
	end
end)
Drag.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		dragInput = input
		
	end
end)
UserInputService.InputChanged:Connect(function(input)
	if input == dragInput and dragging and Drag.Size then
		update(input)
	end
end)


4 Likes

UIDragDetectors exist for this reason, lots of properties to it so you can get the exactly feel you want

1 Like

i heared people say that it was depreciated, is that something else?

They’re new, not sure if they are still in beta though.
Link: Introducing UIDragDetectors [Studio-only Beta]

1 Like

it’s likely because Drag.Position uses UDim2, which doesn’t directly map to the mouse’s AbsolutePosition. Instead, try setting Drag.Position relative to the parent’s AbsoluteSize:

local function update(input)
	local delta = input.Position - dragStart
	Drag.Position = UDim2.new(0, delta.X + startPos.X.Offset, 0, delta.Y + startPos.Y.Offset)
end

this is what i was looking for however it doesnt work on ui gridlayouts which is expected, anyway to bypass this?

UIGridLayouts are very strict with position and size, it wont let you move an object etc…

My idea → Clone the UI you are trying to drag → .Visible = false the one in the UIGridLayout Frame
When the player drags out, then you can :Destroy the one in the UIGridLayout Frame, if they drag back into the inventory just set .Visible back to true

Edit: you probably dont need to clone actually, just reparent it to a corresponding ScreenGUI

i tried both your methods and they both resulted in this:

local gui = script.Parent
local dragdetector = gui.UIDragDetector

dragdetector.DragStart:Connect(function()
	print("dragstart works")
	gui.Parent = gui.Parent.Parent
	local guiclone = gui:Clone()
	guiclone.Position = gui.Position
	guiclone.Parent = gui.Parent.Parent
	gui:Destroy()
end)

you issue comes from this.

try removing this line of code and it should fix it.
Otherwise set the position to Mouse.X and Mouse.Y (Offset)

im a little confused on how i will set the guis position to there mouse cordinates (offset)
is it something like this?

    local mouse = game.Players.LocalPlayer:GetMouse()
	local distance = Vector2.new(mouse.X,mouse.Y) - gui.AbsolutePosition
	guiclone.Position = UDim2.new(0,mouse.X - distance.X,0,mouse.Y - distance.Y)

I believe you can do

local mouse = game.Players.LocalPlayer:GetMouse()
guiclone.Position = UDim2.fromOffset(mouse.X,mouse.Y)

and also ensure gui.Parent.Parent Scale is 1,0,1,0 as i think that may effect the position?

None of these seem to work. Is there a replacement for the UI grid layout?

You could try a UIListLayout and just set the size of your frames using Offset