How to detect if two GUIS are touching

Hello.

I have made up a system that shows a spinning viewport view of any collected items.

It all works, until there are multiple items.

What I would like to do is clone the viewportframe and move it a so that when you collect two items simultaneously, the first items viewport would move out of the way for the viewport.

Here is an example of what I want to do and what it is doing right now:

3 Likes

Try comparing the UDim2 values of them both. You can use that to work out if they are touching, and modify it to fit your needs.

2 Likes

You can express a gui element’s position and rotation as a CFrame (like a part)

local absPos = gui.AbsolutePosition
local absAng = math.rad(gui.AbsoluteRotation)
local absSize = gui.AbsoluteSize

local center = absPos + absSize/2

local cframe = CFrame.new(center.x, center.y, 0)*CFrame.Angles(0, 0, absAng)

If you can generically represent your gui as a series of vertices, like this:

local rectVerts = {
    Vector3.new(-1/2, -1/2, 0),
    Vector3.new(1/2, -1/2, 0),
    Vector3.new(1/2, 1/2, 0),
    Vector3.new(-1/2, 1/2, 0),
}

Then you can write a little code to create a transformed set of vertices which represent exactly where the vertices of your specific gui is.

local function transformVerts(cframe, size, verts)
    local newVerts = {}

    for i, vert in verts do
        newVerts[i] = cframe*(size*vert)
    end

    return newVerts
end

And then we can write a little algorithm to determine if a vertex is within a set of vertices.

local function isPointWithinVerts(point, verts)
    local dir = Vector3.new(1, 0, 0) -- the test direction
    local count = 0 -- the signed number of "walls" we need to pass through, starting from point, going in the direction d, to exit the shape defined by verts
    for i, vert0 in verts do
        local vert1 = verts[i%#verts + 1]
        local rel = vert1 - vert0 -- the difference from one vert to the next in the polygon
        local cr = rel:Cross(dir).z
        local t = rel:Cross(vert0 - point).z/cr
        local s = dir:Cross(vert0 - point).z/cr
        if s < 1 and s >= 0 and t >= 0 then
            count += cr < 0 and -1 or 1
        end
    end

    return count > 0 -- we be inside
end

And finally, we can just test each of the verts of one shape to see if they are inside the other shape.

local function arePolysIntersecting(vertsA, vertsB)
    for i, vertA in vertsA do
        if isPointWithinVerts(vertA, vertsB) then
            return true
        end
    end

    for i, vertB in vertsB do
        if isPointWithinVerts(vertB, vertsA) then
            return true
        end
    end

    return false
end
3 Likes

Woah, big response. I’ll analyze this code and try to understand it better.

I’ll follow up if I get this to work, thank you for this help.