Custom gui selection box wont maintain selected gui's position

im trying to make a selection box that drags the selected GUIs around the screen.

but the problem is the GUIs thats being selected wont maintain the selection box’s position+ the distance between the guis and th selection box postiions. Is there something im doing wrong?

heres the touch script under the selection box
local RunService = game:GetService("RunService")
local Collectionservice = game:GetService("CollectionService")

local group = {}

function areFramesOverlapping(Frame1,Frame2)
	-- X axis overlap detection
	local F1posX,F2posX = Frame1.AbsolutePosition.X,Frame2.AbsolutePosition.X
	local F1sizeX,F2sizeX = Frame1.AbsoluteSize.X,Frame2.AbsoluteSize.X

	local Xdistance = math.abs(F1posX-F2posX) -- distance (in px) between frames
	local minXdistance = math.abs(F1sizeX+F2sizeX/2)-- min distance w/o overlap

	-- Y axis overlap detection
	local F1posY,F2posY = Frame1.AbsolutePosition.Y,Frame2.AbsolutePosition.Y
	local F1sizeY,F2sizeY = Frame1.AbsoluteSize.Y,Frame2.AbsoluteSize.Y

	local Ydistance = math.abs(F1posY-F2posY) -- distance (in px) between frames
	local minYdistance = math.abs(F1sizeY+F2sizeY/2)-- min distance w/o overlap

	if Ydistance < minYdistance and Xdistance < minXdistance then return true end -- OVERLAP!!

	return false -- no overlap detected
end


function OnTouch(b)
	if b == nil then return end
	local a = script.Parent
	local debounce = false
	if areFramesOverlapping(a,b) == true then
			b.UIStroke.Enabled = true
			table.insert(group,b)
			b:setAttribute("distance",b.AbsolutePosition.X-a.AbsolutePosition.X)
			repeat task.wait()
		until areFramesOverlapping(a,b) == false
			b.UIStroke.Enabled = false
			b:setAttribute("distance",0)
			group[b] = nil
	end
end

local guiInset = game:GetService("GuiService"):GetGuiInset()
local function isInScreen(gui)
	local pos = gui.AbsolutePosition + guiInset
	return pos.Y + gui.AbsoluteSize.Y <= (game.Workspace.CurrentCamera.ViewportSize.Y * 2) and pos.Y >= 0
end


game.ReplicatedStorage.Functions.GetSelected.OnInvoke = function()
	return group
end

game.ReplicatedStorage.Events.Deselect.Event:Connect(function()
	table.clear(group)
end)

script.Parent.Destroying:Connect(function()
	for i, v in pairs(group) do
		v.UIStroke.Enabled = false
		group[v] = nil
	end
end)

RunService.Heartbeat:Connect(function()
	for i, b in pairs(Collectionservice:GetTagged("regions")) do
		isInScreen(b)
		if isInScreen(b) == true then
			if script.Parent.BackgroundColor3 == Color3.new(0.333333, 0.333333, 1) then
				coroutine.wrap(OnTouch)(b)
			end
		end
	end
end)
heres the drag script in the selection box
local UserInputService = game:GetService("UserInputService")
local gui = script.Parent

local dragging
local dragInput
local dragStart
local startPos
local tagsystem = game:GetService("CollectionService")
local function filter(number,increment)
	number = math.floor(number)
	number = number-(number%increment)
	return number
end
local Increment = 25

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

end
local debounce = false

gui.InputBegan:Connect(function(input)

	if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then


		if debounce == false then
			debounce = true

			dragging = true

			dragStart = input.Position
			startPos = gui.Position

			input.Changed:Connect(function()
				if input.UserInputState == Enum.UserInputState.End then
					dragging = false
					wait()
					debounce = false

				end
			end)
		end

	end

end)

gui.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		dragInput = input

	end
end)

local pos
UserInputService.InputChanged:Connect(function(input)
	if input == dragInput and dragging then
		update(input)
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			local delta = input.Position - dragStart
			note.Position = UDim2.new(0,gui.AbsolutePosition.X+note:GetAttribute("distance"),0,0)
		end
	end
end)

and heres the script that creates the selection box
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local UIS = game:GetService("UserInputService")
local imageframe = script.Parent.Octaves
local GuiCollisionService = require(game:GetService("ReplicatedStorage").GuiCollisionService)


local function Hovering(Frame)
	local MousePos = game:GetService("UserInputService"):GetMouseLocation() - game:GetService("GuiService"):GetGuiInset()
	local Guis = player:WaitForChild("PlayerGui"):GetGuiObjectsAtPosition(MousePos.X, MousePos.Y)

	for _, Gui in Guis do
		if Gui == Frame then
			return true
		end
	end
	return false
end

UIS.InputBegan:connect(function(input)	

	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		local oldframe = script.Parent:FindFirstChild("Select")
		if oldframe == nil then
			local frame = game.ReplicatedStorage.Assets.Select:Clone()
			frame.Parent = script.Parent
			frame.Name = ("Select")
			frame.BackgroundTransparency = 0.8
			frame.BackgroundColor3 = Color3.new(0.333333, 0.333333, 1)
			local uistroke = Instance.new("UIStroke")
			uistroke.Color = Color3.new(0.333333, 0.333333, 0.498039)
			uistroke.Parent = frame
			frame.Position = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
			repeat
				task.wait()
				frame.Size = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
			until input.UserInputState == Enum.UserInputState.End
		else
			if not Hovering(oldframe) then
				local group = game.ReplicatedStorage.Functions.GetSelected:Invoke()
				for i, region in pairs(group) do
					region.UIStroke.Enabled = false
				end
				oldframe:Destroy()
				local frame = game.ReplicatedStorage.Assets.Select:Clone()
				frame.Parent = script.Parent
				frame.Name = ("Select")
				frame.BackgroundTransparency = 0.8
				frame.BackgroundColor3 = Color3.new(0.333333, 0.333333, 1)
				local uistroke = Instance.new("UIStroke")
				uistroke.Parent = frame
				uistroke.Color = Color3.new(0.333333, 0.333333, 0.498039)
				frame.Position = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
				repeat
					task.wait()
					frame.Size = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
				until input.UserInputState == Enum.UserInputState.End
			end
		end
	end
end)



UIS.InputEnded:connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		wait()
		local frame = script.Parent:FindFirstChild("Select")
		if frame ~= nil then
			local selected = script.Parent.Select		
			selected.BackgroundColor3 = Color3.new(0.333333, 0.333333, 0.498039)
			wait(0.1)
			local nearestPos = 100000
			local furthestPos = 0
			local LowestPos = 0
			local HighestPos = 10000
			local nearest = nil
			local furthest = nil
			local highest = nil
			local distance = nil
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				if note == nil then
					selected:Destroy()
					return 
				end
				local distance = note.AbsolutePosition.X

				if distance < nearestPos then
					nearestPos = distance
					 nearest = note
					selected.Position = UDim2.new(UDim.new(0,nearest.Position.X.Offset),selected.Position.Y)
				end
			end
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				if note == nil then return end
				local distance = note.AbsolutePosition.X+note.AbsoluteSize.X
				if distance > furthestPos then
					furthestPos = distance
					 furthest = note
					selected.Size = UDim2.new(UDim.new(0,furthest.Position.X.Offset-nearest.Position.X.Offset+furthest.Size.X.Offset),selected.Size.Y)
				end
			end
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				if note == nil then return end
				local distance = note.AbsolutePosition.Y
				if distance < HighestPos then
					
					HighestPos = distance
					 highest = note
					selected.Position = UDim2.new(selected.Position.X,UDim.new(0,highest.AbsolutePosition.Y-highest.Parent.Parent.Parent.AbsolutePosition.Y))
				end
			end
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				if note == nil then return end
				 distance = note.AbsolutePosition.Y
				if distance > LowestPos then
					LowestPos = distance
					local lowest = note
					local desiredAbsolutePosition = lowest.AbsolutePosition
					local relativePosition = desiredAbsolutePosition - selected.Parent.AbsolutePosition
					selected.Size = UDim2.new(selected.Size.X,UDim.new(0,lowest.AbsolutePosition.Y-highest.AbsolutePosition.Y+lowest.AbsoluteSize.Y))
				end
			end
		else
			return
		end	
	end
end)

imageframe.MouseLeave:Connect(function()
	wait()
	local frame = script.Parent:FindFirstChild("Select")
	if frame ~= nil then
		local selected = script.Parent.Select		
		selected.BackgroundColor3 = Color3.new(0.333333, 0.333333, 0.498039)
		wait(0.1)
		local nearestPos = 100000
		local furthestPos = 0
		local LowestPos = 0
		local HighestPos = 10000
		local nearest = nil
		local furthest = nil
		local highest = nil
		local distance = nil
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then
				selected:Destroy()
				return
			end
			local distance = note.AbsolutePosition.X

			if distance < nearestPos then
				nearestPos = distance
				nearest = note
				selected.Position = UDim2.new(UDim.new(0,nearest.Position.X.Offset),selected.Position.Y)
			end
		end
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then return end
			local distance = note.AbsolutePosition.X+note.AbsoluteSize.X
			if distance > furthestPos then
				furthestPos = distance
				furthest = note
				selected.Size = UDim2.new(UDim.new(0,furthest.Position.X.Offset-nearest.Position.X.Offset+furthest.Size.X.Offset),selected.Size.Y)
			end
		end
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then return end
			local distance = note.AbsolutePosition.Y
			if distance < HighestPos then

				HighestPos = distance
				highest = note
				selected.Position = UDim2.new(selected.Position.X,UDim.new(0,highest.AbsolutePosition.Y-highest.Parent.Parent.Parent.AbsolutePosition.Y))
			end
		end
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then return end
			distance = note.AbsolutePosition.Y
			if distance > LowestPos then
				LowestPos = distance
				local lowest = note
				local desiredAbsolutePosition = lowest.AbsolutePosition
				local relativePosition = desiredAbsolutePosition - selected.Parent.AbsolutePosition
				selected.Size = UDim2.new(selected.Size.X,UDim.new(0,lowest.AbsolutePosition.Y-highest.AbsolutePosition.Y+lowest.AbsoluteSize.Y))
			end
		end
	else
		return
	end	
end)

i figured it out, i was setting the attribute(distance) when it was touched, even if the selection box hasnt been released yet.

i moved this code

b:setAttribute("distance",b.AbsolutePosition.X-a.AbsolutePosition.X)

into the drag script. and will set the attribute after the player releases the selection box.

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local UIS = game:GetService("UserInputService")
local imageframe = script.Parent.Octaves
local GuiCollisionService = require(game:GetService("ReplicatedStorage").GuiCollisionService)


local function Hovering(Frame)
	local MousePos = game:GetService("UserInputService"):GetMouseLocation() - game:GetService("GuiService"):GetGuiInset()
	local Guis = player:WaitForChild("PlayerGui"):GetGuiObjectsAtPosition(MousePos.X, MousePos.Y)

	for _, Gui in Guis do
		if Gui == Frame then
			return true
		end
	end
	return false
end

UIS.InputBegan:connect(function(input)	

	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		local oldframe = script.Parent:FindFirstChild("Select")
		if oldframe == nil then
			local frame = game.ReplicatedStorage.Assets.Select:Clone()
			frame.Parent = script.Parent
			frame.Name = ("Select")
			frame.BackgroundTransparency = 0.8
			frame.BackgroundColor3 = Color3.new(0.333333, 0.333333, 1)
			local uistroke = Instance.new("UIStroke")
			uistroke.Color = Color3.new(0.333333, 0.333333, 0.498039)
			uistroke.Parent = frame
			frame.Position = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
			repeat
				task.wait()
				frame.Size = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
			until input.UserInputState == Enum.UserInputState.End
		else
			if not Hovering(oldframe) then
				local group = game.ReplicatedStorage.Functions.GetSelected:Invoke()
				for i, region in pairs(group) do
					region.UIStroke.Enabled = false
				end
				oldframe:Destroy()
				local frame = game.ReplicatedStorage.Assets.Select:Clone()
				frame.Parent = script.Parent
				frame.Name = ("Select")
				frame.BackgroundTransparency = 0.8
				frame.BackgroundColor3 = Color3.new(0.333333, 0.333333, 1)
				local uistroke = Instance.new("UIStroke")
				uistroke.Parent = frame
				uistroke.Color = Color3.new(0.333333, 0.333333, 0.498039)
				frame.Position = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
				repeat
					task.wait()
					frame.Size = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
				until input.UserInputState == Enum.UserInputState.End
			end
		end
	end
end)



UIS.InputEnded:connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		wait()
		local frame = script.Parent:FindFirstChild("Select")
		if frame ~= nil then
			local selected = script.Parent:FindFirstChild("Select")
			if selected == nil then return end
			selected.BackgroundColor3 = Color3.new(0.333333, 0.333333, 0.498039)
			wait(0.1)
			local nearestPos = 100000
			local furthestPos = 0
			local LowestPos = 0
			local HighestPos = 10000
			local nearest = nil
			local furthest = nil
			local highest = nil
			local distance = nil
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				note:setAttribute("distance",note.AbsolutePosition.X-selected.AbsolutePosition.X)
				if note == nil then
					selected:Destroy()
					return 
				end
				local distance = note.AbsolutePosition.X

				if distance < nearestPos then
					nearestPos = distance
					 nearest = note
					selected.Position = UDim2.new(UDim.new(0,nearest.Position.X.Offset),selected.Position.Y)
				end
			end
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				if note == nil then return end
				local distance = note.AbsolutePosition.X+note.AbsoluteSize.X
				if distance > furthestPos then
					furthestPos = distance
					 furthest = note
					selected.Size = UDim2.new(UDim.new(0,furthest.Position.X.Offset-nearest.Position.X.Offset+furthest.Size.X.Offset),selected.Size.Y)
				end
			end
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				if note == nil then return end
				local distance = note.AbsolutePosition.Y
				if distance < HighestPos then
					
					HighestPos = distance
					 highest = note
					selected.Position = UDim2.new(selected.Position.X,UDim.new(0,highest.AbsolutePosition.Y-highest.Parent.Parent.Parent.AbsolutePosition.Y))
				end
			end
			for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
				if note == nil then return end
				 distance = note.AbsolutePosition.Y
				if distance > LowestPos then
					LowestPos = distance
					local lowest = note
					local desiredAbsolutePosition = lowest.AbsolutePosition
					local relativePosition = desiredAbsolutePosition - selected.Parent.AbsolutePosition
					selected.Size = UDim2.new(selected.Size.X,UDim.new(0,lowest.AbsolutePosition.Y-highest.AbsolutePosition.Y+lowest.AbsoluteSize.Y))
				end
			end
			
		else
			return
		end	
	end
end)

imageframe.MouseLeave:Connect(function()
	wait()
	local frame = script.Parent:FindFirstChild("Select")
	if frame ~= nil then
		local selected = script.Parent.Select		
		selected.BackgroundColor3 = Color3.new(0.333333, 0.333333, 0.498039)
		wait(0.1)
		local nearestPos = 100000
		local furthestPos = 0
		local LowestPos = 0
		local HighestPos = 10000
		local nearest = nil
		local furthest = nil
		local highest = nil
		local distance = nil
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then
				selected:Destroy()
				return
			end
			local distance = note.AbsolutePosition.X

			if distance < nearestPos then
				nearestPos = distance
				nearest = note
				selected.Position = UDim2.new(UDim.new(0,nearest.Position.X.Offset),selected.Position.Y)
			end
		end
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then return end
			local distance = note.AbsolutePosition.X+note.AbsoluteSize.X
			if distance > furthestPos then
				furthestPos = distance
				furthest = note
				selected.Size = UDim2.new(UDim.new(0,furthest.Position.X.Offset-nearest.Position.X.Offset+furthest.Size.X.Offset),selected.Size.Y)
			end
		end
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then return end
			local distance = note.AbsolutePosition.Y
			if distance < HighestPos then

				HighestPos = distance
				highest = note
				selected.Position = UDim2.new(selected.Position.X,UDim.new(0,highest.AbsolutePosition.Y-highest.Parent.Parent.Parent.AbsolutePosition.Y))
			end
		end
		for i, note in pairs(game.ReplicatedStorage.Functions.GetSelected:Invoke()) do
			if note == nil then return end
			distance = note.AbsolutePosition.Y
			if distance > LowestPos then
				LowestPos = distance
				local lowest = note
				local desiredAbsolutePosition = lowest.AbsolutePosition
				local relativePosition = desiredAbsolutePosition - selected.Parent.AbsolutePosition
				selected.Size = UDim2.new(selected.Size.X,UDim.new(0,lowest.AbsolutePosition.Y-highest.AbsolutePosition.Y+lowest.AbsoluteSize.Y))
			end
		end
	else
		return
	end	
end)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.