Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

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

Asked by 6 years ago
Edited 6 years ago

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

Log in to vote
1
Answered by
EgoMoose 802 Moderation Voter
6 years ago

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
Ad

Answer this question