Calculate which frame collides most

Hello, the question is fairly simple - I have 1 frame and a table of a few frames (5). I need to detect with which frame does my given frame overlap most. I got it working to check if it collides at all.

function areFramesOverlapping(mainFrame, frames)
	local collidingFrames = {}
	
	local mainFrame_topLeft = mainFrame.AbsolutePosition
	local mainFrame_bottomRight = mainFrame_topLeft + mainFrame.AbsoluteSize
	
	for _, frame in ipairs(frames) do
		local frame_topLeft = frame.AbsolutePosition
		local frame_bottomRight = frame_topLeft + frame.AbsoluteSize
		
		if (mainFrame_topLeft.x < frame_bottomRight.x and mainFrame_bottomRight.x > frame_topLeft.x) and (mainFrame_topLeft.y < frame_bottomRight.y and mainFrame_bottomRight.y > frame_topLeft.y) then
			table.insert(collidingFrames, frame)
		end
	end

	return collidingFrames
end

This currently returns a table of frames which over a given frame collides with. Now how could I remake this to return the frame with which frame1 collides the most? I am happy to answer any more questions

What do you mean by “most”? Given a rectangular area of overlap for each frame, should the one with the largest area of overlap win, or the one with longest diagonal, or the one with the longest side length?

Overally the most area. I can give you an example :


Here you can see I have 5 frames and I main frame (Item 11) and it collides most with the frame 3 because its total area of collision is bigger then with any other frame. Now how would I go about it to implement it in the code?

i think this post will work for you 2 Dimensional Collisions | Fundamentals & Techniques

function DetectCollision(A, B)
if (B.AbsolutePosition.x <= A.AbsolutePosition.x + A.AbsoluteSize.x) then
return true – colliding
end

return false

end

This is what i think i already have - it just checks for collision and doesnt check which frame collides most

while this is not what your asking here is a more simple method

local frames = script.xxxxxxx:GetChildren()

local draggingFrame = xxxxxx
local draggingCenter = draggingFrame.AbsolutePosition + (draggingFrame.AbsoluteSize * 0.5)

local function GetClosestFrame()
    local closestFrame = nil
    local closestMagnitude = math.huge
    for i, frame in ipairs(frames) do
        local center = frame.AbsolutePosition + (frame.AbsoluteSize * 0.5)
        local magnitude = (center - draggingCenter).Magnitude
        if magnitude >= closestMagnitude then continue end
        closestFrame = frame
        closestMagnitude = magnitude
    end
    return closestFrame, closestMagnitude
end

local frame, magnitude = GetClosestFrame()
print(frame, magnitude)


local minDistance = math.max(draggingFrame.AbsoluteSize.X, draggingFrame.AbsoluteSize.Y) * 2

if magnitude <= minDistance then
    print("In range")
else
    print("Out of range")
end

Hm yes it’s very similar and maybe more clear but does anyone know how could I at least calculate the area of the collision? @5uphi wouldn’t I just multiply the difference in X and difference in Y if it collides and then compare this to other colliding frame?


I think comparing the colliding areas would work just fine but how could I get A2, B2, A3, B3? (see screenshot)

i have not tested this code

local function Area(frame1, frame2)
    local f1 = {
        frame1.AbsolutePosition.X,
        frame1.AbsolutePosition.Y,
        frame1.AbsolutePosition.X + frame1.AbsoluteSize.X
        frame1.AbsolutePosition.Y + frame1.AbsoluteSize.Y
    } 
    local f2 = {
        frame2.AbsolutePosition.X,
        frame2.AbsolutePosition.Y,
        frame2.AbsolutePosition.X + frame2.AbsoluteSize.X
        frame2.AbsolutePosition.Y + frame2.AbsoluteSize.Y
    } 
    local dx = math.max(math.max(f1[1], f2[1]) - math.min(f1[3], f2[3]), 0)
    local dy = math.max(math.max(f1[2], f2[2]) - math.min(f1[4], f2[4]), 0)
    return dx * dy
end

The final code

-- To get the frames which collide with the mainFrame
function areFramesOverlapping(mainFrame, frames)
	local collidingFrames = {}
	
	local mainFrame_topLeft = mainFrame.AbsolutePosition
	local mainFrame_bottomRight = mainFrame_topLeft + mainFrame.AbsoluteSize
	
	for _, frame in ipairs(frames) do
		local frame_topLeft = frame.AbsolutePosition
		local frame_bottomRight = frame_topLeft + frame.AbsoluteSize
		
		if (mainFrame_topLeft.x < frame_bottomRight.x and mainFrame_bottomRight.x > frame_topLeft.x) and (mainFrame_topLeft.y < frame_bottomRight.y and mainFrame_bottomRight.y > frame_topLeft.y) then
			table.insert(collidingFrames, frame)
		end
	end

	return collidingFrames
end
-- To get closest frame of colliding frames
local function GetClosestFrame(draggingFrame, frames)
	local draggingCenter = draggingFrame.AbsolutePosition + (draggingFrame.AbsoluteSize * 0.5)
	local closestFrame = nil
	local closestMagnitude = math.huge
	for i, frame in ipairs(frames) do
		local center = frame.AbsolutePosition + (frame.AbsoluteSize * 0.5)
		local magnitude = (center - draggingCenter).Magnitude
		if magnitude >= closestMagnitude then continue end
		closestFrame = frame
		closestMagnitude = magnitude
	end
	return closestFrame
end

Calling the functions →

local closestFrame = GetClosestFrame(dragFrame.Object, areFramesOverlapping(dragFrame.Object, pets))
print(closestFrame)

(I know the code’s a mess and can be simpler/prettier)
I’ve split it to 2 functions like this to also check the Y axis
(pets here is a table of frames)
Basing on @5uphi answer

no problem i’m happy i helped.

2 Likes