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

Surface touching something?

Asked by 7 years ago

I need to find out if the surface of a certain part is touching a part. For example, if the part's bottom surface is touching a different part, it would return true, otherwise false. However if that same part's top surface was touching a part that would not matter, it would only see if the bottom surface of a part is touching something.

2 answers

Log in to vote
1
Answered by 7 years ago

Move it

This assumes that your part isn't actually intersecting with another part, and that you don't need the part which it's touching.

local function IsTouchingForward(p, closeness)
  local closeness = closeness or 0.1;
  local tmp = p.CFrame;
  local tmpp = (tmp*Vector3.new(0,0,-closeness);
  p.Position = tmpp;
  local r = p.Position ~= tmpp;
  p.CFrame = tmp;
  return r;
end;

This checks if there's something which it can collide with 0.1 studs infront of it. You can change the vector and closeness to tune it to suit.

Ad
Log in to vote
0
Answered by
EgoMoose 802 Moderation Voter
7 years ago

This is a fun question!

Another possibility is to do some plane intersections along with culling. The calculation is way more intense, but the answer is more accurate and allows you to test specific parts. I'd still rcmd using eLunate's tho if it doesn't matter.

function planeIntersect(point, vector, origin, normal)
    -- see this blog post: https://scriptinghelpers.org/blog/silhouettes-and-shadows
    local rpoint = point - origin;
    local t = -rpoint:Dot(normal) / vector:Dot(normal);
    return point + t * vector, t;
end;

function surfaceCollision(part, normalid, otherpart)
    local planes, corners = {}, {};
    -- get the planes that make up the surfaces
    for _, enum in next, Enum.NormalId:GetEnumItems() do
        local lnormal = Vector3.FromNormalId(enum);
        local wnormal = part.CFrame:vectorToWorldSpace(lnormal);
        local distance = (lnormal * part.Size/2).magnitude;
        local point = part.CFrame.p + wnormal * distance;
        planes[enum] = {
            normal = wnormal;
            point = point;
        };
    end;
    -- get corners of thing you're checking
    for x = -1, 1, 2 do
        for y = -1, 1, 2 do
            for z = -1, 1, 2 do
                table.insert(corners, (otherpart.CFrame * CFrame.new(otherpart.Size/2 * Vector3.new(x, y, z))).p);
            end;
        end;
    end;
    -- collision lines
    local attach = {
        [corners[1]] = {corners[3], corners[2], corners[5]};
        [corners[4]] = {corners[3], corners[2], corners[8]};
        [corners[6]] = {corners[5], corners[2], corners[8]};
        [corners[7]] = {corners[3], corners[8], corners[5]};
    };
    -- check each line against the surface plane chosen
    for point, set in next, attach do
        for _, corner in next, set do
            local v = corner - point;
            local p, t = planeIntersect(point, v, planes[normalid].point, planes[normalid].normal);
            if t <= 1.001 and t  >= 0 then -- minor margin of error to account for float math error
                local pass = true;
                for key, plane in next, planes do
                    if key ~= normalid then
                        local r = point - plane.point;
                        if r:Dot(plane.normal) >= 0 then
                            pass = false;
                        end;
                    end;
                end;
                if pass then return true; end;
            end;
        end;
    end;
    return false;
end;

Example in action: http://i.imgur.com/6aeVvMe.gif

Answer this question