Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Trying to implement 2D gui collision physics properly, help?

This right here is a script collated directly from EgoMoose's tutorial on how to implement 2D collision with rotation. Works perfectly. (Thanks! @Egomoose, if you are reading this.) But I have no idea how I would implement this into my own 2D engine without messing things up. My 2D enigne just has 2D collision without the support of rotation. The script from my 2D engine is below this script right here.

local f1 = script.Parent:WaitForChild("Frame1");
local f2 = script.Parent:WaitForChild("Frame2");

function getPerpendicular(vec)
    return Vector2.new(vec.y, -vec.x).unit;
end;

function getAxis(shape1Corners, shape2Corners)
    local axis = {};
    axis[1] = getPerpendicular(shape1Corners[1] - shape1Corners[2]);
    axis[2] = getPerpendicular(shape1Corners[1] - shape1Corners[4]);
    axis[3] = getPerpendicular(shape2Corners[1] - shape2Corners[2]);
    axis[4] = getPerpendicular(shape2Corners[1] - shape2Corners[4]);
    return axis;
end;

function getAxis(shape1Corners, shape2Corners)
    local axis = {};
    -- it doesn't matter if the vector's x and y values are positive or negative (just no repeats via opposite vectors)
    axis[1] = (shape1Corners[2] - shape1Corners[1]).unit;
    axis[2] = (shape1Corners[2] - shape1Corners[3]).unit;
    axis[3] = (shape2Corners[2] - shape2Corners[1]).unit;
    axis[4] = (shape2Corners[2] - shape2Corners[3]).unit;
    return axis;
end;

function getAxis(c1, c2)
	local axis = {};
	axis[1] = (c1[2] - c1[1]).unit;
	axis[2] = (c1[4] - c1[1]).unit;
	axis[3] = (c2[2] - c2[1]).unit;
	axis[4] = (c2[4] - c2[1]).unit;
	return axis;
end;

function dot2d(a, b)
    -- dot product for vector2
    return a.x * b.x + a.y * b.y;
end;

function collide(shape1, shape2)
	local c1, c2 = getCorners(shape1), getCorners(shape2);
	local axis = getAxis(c1, c2);
	local scalars, mtv = {}, Vector2.new(math.huge, math.huge); -- huge magnitude
	local a = nil;
	for i = 1, #axis do
		for i2, set in pairs({c1, c2}) do
			scalars[i2] = {};
			for _, point in pairs(set) do
				table.insert(scalars[i2], dot2d(point, axis[i]));
			end;
		end;
		local s1max, s1min = math.max(unpack(scalars[1])), math.min(unpack(scalars[1]));
		local s2max, s2min = math.max(unpack(scalars[2])), math.min(unpack(scalars[2]));
		if s2min > s1max or s2max < s1min then
			return false, Vector2.new(); -- mtv is nothing because there isn't collision
		end;
		-- we are getting the overlap of shape 1 on shape 2 which means we apply the mtv onto shape 2
		local overlap = s1max > s2max and -(s2max - s1min) or (s1max - s2min);
		if math.abs(overlap) < mtv.magnitude then
			-- overlap might be negative to account for proper direction
			mtv = axis[i] * overlap;
		end;
	end;
	return true, mtv;
end;
 
-- example
 
game:GetService("RunService").RenderStepped:connect(function()
	f1.Rotation = f1.Rotation + 1;
	f2.Rotation = f2.Rotation - 1;
	local doesCollide, mtv = collide(f2, f1);
	if doesCollide then
		f1.Position = f1.Position + UDim2.new(0, mtv.x, 0, mtv.y);
	end;
end);
 


Right here!


tether = function(frame)
	local hb = frame:FindFirstChild("hitbox")
	if not hb then print'no hitbox found' out('missing hitbox < error') return end
	local v = hb:FindFirstChild("velocity")	--Vector3
	local m = hb:FindFirstChild("motion")	--Vector3
	local b = hb:FindFirstChild("bounce")	--Vector3
	if not (v or m) then print'missingno' out('missing property < error') return end
	local data = fg:GetChildren()
	
	--applying physical limitations with seemingly no rotation...-- 
v.Value = Vector3.new(m.Value.X==1 and math.min(v.Value.X-unit>0 and v.Value.X-unit or (v.Value.X+unit<0 and v.Value.X+unit or 0),terminal_velocity) or m.Value.X,m.Value.Y==1 and math.min(v.Value.Y+gravity,terminal_velocity) or m.Value.Y,0)
	
	for _,obj in next, data do if obj~=frame then check_hit(frame,obj,v) end end
	if frame~=player then check_hit(frame,player,v) end
	
	if b then
		if b.Value.Z>=1 then b.Value = Vector3.new(b.Value.X,b.Value.Y,b.Value.Z-1) print'delayed' elseif b.Value~=Vector3.new(0,0,0) then print'successful'
			v.Value = v.Value + b.Value b.Value = Vector3.new(0,0,0)
		end
	end
	
	frame.Position = frame.Position + UDim2.new(v.Value.X,0,v.Value.Y,0)
	
end

1 answer

If I'm reading this right then you're looking at line 13 and 14 of your code.

You just want to update it so that you move them out of collision if you need to:

for _,obj in next, data do 
	if obj~=frame then 
		local collision, mtv = collide(obj, frame);
		if (collision) then
			frame.Position = frame.Position + UDim2.new(0, mtv.x, 0, mtv.y);
		end;
	end 
end

if frame ~= player then 
	local collision, mtv = collide(player, frame);
	if (collision) then
		frame.Position = frame.Position + UDim2.new(0, mtv.x, 0, mtv.y);
	end;
end

This discussion is preserved as it was. New answers, comments, and votes are closed.