Im trying to code a selection gui(the white frame studio has around the two guis
but im trying to code it to where it works no matter if the ancestors arent the same or if its using “offset or scale” but is doesnt work
heres my code
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.666667, 0, 0)
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)
while true do
task.wait()
frame.Size = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
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.666667, 0, 0)
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)
while true do
task.wait()
frame.Size = UDim2.new(0, mouse.X - frame.AbsolutePosition.X, 0, mouse.Y - frame.AbsolutePosition.Y)
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:Clone()
selected.Parent = frame.Parent
selected.BackgroundColor3 = Color3.new(0.333333, 0.333333, 0.498039)
frame.Size = UDim2.new(frame.AbsoluteSize.X, frame.AbsoluteSize.Y)
frame:destroy()
wait(0.2)
local group = game.ReplicatedStorage.Functions.GetSelected:Invoke()
local nearestPos = 100000
local furthestPos = 0
local nearest
local furthest
for i, note in pairs(group) do
local distance = (note.AbsolutePosition-script.Parent.AbsolutePosition).Magnitude
if distance < nearestPos then
nearestPos = distance
nearest = note
end
end
for i, note in pairs(group) do
local distance = (note.AbsolutePosition-script.Parent.AbsolutePosition).Magnitude
if distance > nearestPos then
furthestPos = distance
furthest = note
end
end
local corners = GuiCollisionService:getGuiCorners(nearest.Parent)
if corners == nil then return end
selected.Position = UDim2.new(0,nearest.Position.X.Offset,0, nearest.AbsoluteSize.Y + nearest.Parent.Position.Y.Offset)
print(selected.Position)
else
return
end
end
end)
imageframe.MouseLeave:Connect(function()
wait()
local frame = script.Parent:FindFirstChild("Select")
if frame ~= nil then
local Select = script.Parent.Select:Clone()
Select.Parent = frame.Parent
Select.BackgroundColor3 = Color3.new(0.333333, 0.333333, 0.498039)
frame.Size = UDim2.new(frame.AbsoluteSize.X, frame.AbsoluteSize.Y)
frame:destroy()
else
return
end
end)
and hers the gui collision service(got it from RuizuKun_Dev)
local GuiCollisionService = {}
GuiCollisionService.__index = GuiCollisionService
local mouse = game.Players.LocalPlayer:GetMouse()
local function intersects (p, edge)
local x1, y1 = edge.a.X, edge.a.Y
local x2, y2 = edge.b.X, edge.b.Y
local x3, y3 = p.X, p.Y
local x4, y4 = p.X + 2147483647, p.Y
local den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
if den == 0 then return false end
local t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den
local u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den
if t and u and t > 0 and t < 1 and u > 0 then
return true
end
return false
end
local function solidCollision(gui1,gui2) -- special thanks to RuizuKun_Dev
local pos1, size1 = gui1.AbsolutePosition, gui1.AbsoluteSize;
local pos2, size2 = gui2.AbsolutePosition, gui2.AbsoluteSize;
local IsColliding, MTV = GuiCollisionService.isColliding(gui1, gui2)
if IsColliding then
local EdgeDifferences_Array = {
Vector2.new(pos1.X - (pos2.X + size2.X), 0);
Vector2.new((pos1.X + size1.X) - pos2.X, 0);
Vector2.new(0, pos1.Y - (pos2.Y + size2.Y));
Vector2.new(0, (pos1.Y + size1.Y) - pos2.Y);
};
table.sort(EdgeDifferences_Array, function(A, B) return A.magnitude < B.magnitude; end);
MTV = EdgeDifferences_Array[1];
end;
return IsColliding, MTV or Vector2.new();
end;
local function getCorners(guiObject0)
local pos = Vector2.new(guiObject0.Position.X.Offset,guiObject0.Position.Y.Offset)
local size = Vector2.new(guiObject0.Size.X.Offset,guiObject0.Size.Y.Offset)
local rotation = guiObject0.Rotation--Change offset to scale if you want
local a = pos + size/2 - math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) + math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) + math.atan2(size.Y, size.X)))
local b = pos + size/2-math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) - math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) - math.atan2(size.Y, size.X)))
local c = pos + size/2+math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) + math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) + math.atan2(size.Y, size.X)))
local d = pos + size/2+math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) - math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) - math.atan2(size.Y, size.X)))
return{
topleft = a,
bottomleft = b,
topright = d,
bottomright = c
}
end
local function checkCollisions(collider, hitter)
if collider.solid then
local IsColliding, MTV = solidCollision(hitter.i, collider.i);
if IsColliding then
if hitter.t then
for i, tween in ipairs(hitter.t) do
if tween.PlaybackState == Enum.PlaybackState.Playing then
tween:Pause()
table.remove(hitter.t, i)
end
end
end
hitter.i.Position = hitter.i.Position - UDim2.new(0, MTV.X, 0, MTV.Y);
end;
end
if GuiCollisionService.isColliding(hitter.i, collider.i) then
return true
end
return false
end
local function check (hitter, colliders, h)
local collidingWith = {}
for _, collider in ipairs(colliders) do
if h then
if hitter.i.ZIndex == collider.i.ZIndex then
if checkCollisions(collider, hitter) then
table.insert(collidingWith, collider.i)
end
end
else
if checkCollisions(collider, hitter) then
table.insert(collidingWith, collider.i)
end
end
end
if #collidingWith > 0 then
return collidingWith
end
return nil
end
local function inRange(num, range)
return num > range.Min and num < range.Max
end
function GuiCollisionService:MouseBetweenPoints(pointA,pointB)
local mouseVector = Vector2.new(mouse.X,mouse.Y)
local pointAVector = Vector2.new(pointA.X.Offset,pointA.Y.Offset)
local pointBVector = Vector2.new(pointB.X.Offset,pointB.Y.Offset)
return ((mouseVector.X > pointAVector.X and mouseVector.Y > pointAVector.Y) and (mouseVector.X < pointBVector.X and mouseVector.Y < pointBVector.Y))
end
function GuiCollisionService:MouseInFrame(frame)
local pointAVector = frame.AbsolutePosition
local pointBVector = frame.AbsolutePosition + frame.AbsoluteSize
return GuiCollisionService:MouseBetweenPoints(UDim2.fromOffset(pointAVector.X,pointAVector.Y),UDim2.fromOffset(pointBVector.X,pointBVector.Y))
end
function GuiCollisionService:getGuiCorners(guiObject0)
if guiObject0 == nil then return end
local pos = Vector2.new(guiObject0.Position.X.Offset,guiObject0.Position.Y.Offset)
local size = Vector2.new(guiObject0.Size.X.Offset,guiObject0.Size.Y.Offset)
local rotation = guiObject0.Rotation--Change offset to scale if you want
local a = pos + size/2-math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) + math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) + math.atan2(size.Y, size.X)))
local b = pos + size/2-math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) - math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) - math.atan2(size.Y, size.X)))
local c = pos + size/2+math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) + math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) + math.atan2(size.Y, size.X)))
local d = pos + size/2+math.sqrt((size.X/2)^2 + (size.Y/2)^2) * Vector2.new(math.cos(math.rad(rotation) - math.atan2(size.Y, size.X)), math.sin(math.rad(rotation) - math.atan2(size.Y, size.X)))
return{
topleft = a,
bottomleft = b,
topright = d,
bottomright = c
}
end
function GuiCollisionService.isInCore(gui0, gui1)
assert(typeof(gui0) == "Instance" and typeof(gui1) == "Instance", "argument must be an instance")
if gui0.AbsoluteSize.X > gui1.X or gui0.AbsolutePosition.Y > gui1.Y then return false end
local corners0, corners1 = getCorners(gui0), getCorners(gui1)
local X = NumberRange.new(corners1[1].X, corners1[4].X)
local Y = NumberRange.new(corners1[1].Y, corners1[2].Y)
local cornersInside = 0
for _, corner in ipairs(corners0) do
if inRange(corner.X, X) and inRange(corner.Y, Y) then
cornersInside += 1
end
end
if cornersInside == 4 then
return true
end
return false
end
function GuiCollisionService.isColliding(guiObject0, guiObject1)
if not typeof(guiObject0) == "Instance" or not typeof(guiObject1) == "Instance" then error("argument must be an instance") return end
local ap1 = guiObject0.Position.X.Offset
local as1 = guiObject0.Size.X.Offset
local sum = ap1 + as1
local ap2 = guiObject1.Position.X.Offset
local as2 = guiObject1.Size.X.Offset
local sum2 = ap2 + as2
local corners0 = getCorners(guiObject0)
local corners1 = getCorners(guiObject1)
local edges = {
{
a = corners1.topleft,
b = corners1.bottomleft
},
{
a = corners1.topleft,
b = corners1.topright
},
{
a = corners1.bottomleft,
b = corners1.bottomright
},
{
a = corners1.topright,
b = corners1.bottomright
}
}
local collisions = 0
for _, corner in pairs(corners0) do
for _, edge in pairs(edges) do
if intersects(corner, edge) then
collisions += 1
end
end
end
if collisions%2 ~= 0 then
return true
end
if (ap1 < sum2 and sum > ap2) then
return true
end
return false
end
function GuiCollisionService.createCollisionGroup()
local collisionDetected = Instance.new("BindableEvent")
local self = setmetatable({
ColliderTouched = collisionDetected.Event
}, GuiCollisionService)
self.colliders = {}
self.hitters = {}
self.hierarchy = false
game:GetService("RunService").RenderStepped:Connect(function(dt)
for _, hitter in ipairs(self.hitters) do
local res = check(hitter, self.colliders, self.hierarchy)
if res then
local bin = {}
for i, v in ipairs(res) do
if table.find(bin, v) then
table.remove(res, i)
else
table.insert(bin, v)
end
end
hitter.i.CollidersTouched:Fire(res)
hitter.i.Colliding.Value = true
return
else
hitter.i.Colliding.Value = false
end
hitter.i.Colliding:GetPropertyChangedSignal("Value"):Connect(function()
if not hitter.i.Colliding.Value then
hitter.i.OnCollisionEnded:Fire()
return
end
end)
end
end)
return self
end
function GuiCollisionService:setZIndexHierarchy(bool: boolean)
assert(typeof(bool) == "boolean", "argument must be a boolean")
self.hierarchy = true
end
function GuiCollisionService:addHitter(instance, tweens: table)
assert(typeof(instance) == "Instance", "argument must be an instance")
assert(typeof(tweens) == "table", "argument must be a table")
local be = Instance.new("BindableEvent")
be.Name = "CollidersTouched"
be.Parent = instance
local be2 = be:Clone()
be2.Name = "OnCollisionEnded"
be2.Parent = instance
local is = Instance.new("BoolValue")
is.Name = "Colliding"
is.Value = false
is.Parent = instance
table.insert(self.hitters, { i = instance, t = tweens })
return { index = #self.hitters, ["instance"] = instance }
end
function GuiCollisionService:updateHitter(i: number, instance, tweens: table)
assert(typeof(i) == "number", "argument must be a table")
assert(typeof(instance) == "Instance", "argument must be an instance")
assert(typeof(tweens) == "table", "argument must be a table")
self.hitters[i] = { i = instance, t = tweens or {} }
return { index = i, instance = self.hitters[i].i }
end
function GuiCollisionService:getHitter(index)
return self.hitters[index].i
end
function GuiCollisionService:getHitterTweens(index)
return self.hitters[index].t
end
function GuiCollisionService:getHitters()
local res = {}
for _, v in ipairs(self.hitters) do
table.insert(res, v.i)
end
return res
end
function GuiCollisionService:removeHitter(index)
table.remove(self.hitters, index)
end
function GuiCollisionService:addCollider(instance, t: boolean)
assert(typeof(instance) == "Instance", "argument must be an instance")
assert(typeof(t) == "boolean", "argument must be a boolean")
if not self.colliders then
self.colliders = {}
end
if t then
table.insert(self.colliders, { i = instance, solid = true })
else
table.insert(self.colliders, { i = instance })
end
return { index = #self.colliders, ["instance"] = instance, solid = t }
end
function GuiCollisionService:updateCollider(i: number, instance, t: boolean)
assert(typeof(i) == "number", "argument must be a table")
assert(typeof(instance) == "Instance", "argument must be an instance")
assert(typeof(t) == "boolean", "argument must be a boolean")
self.colliders[i] = { ["i"] = instance, solid = t }
return { index = i, instance = self.colliders[i].i, self.colliders[i].solid }
end
function GuiCollisionService:getColliders()
local res = {}
for _, v in ipairs(self.colliders) do
table.insert(res, v.i)
end
return res
end
function GuiCollisionService:removeCollider(index)
table.remove(self.colliders, index)
end
return GuiCollisionService