Source for those who’d rather not download a file:
local insidePolygon do
function insidePolygon(polygon, p)
local isInside = false
local minX = polygon[1].x; local maxX = polygon[1].x
local minY = polygon[1].z; local maxY = polygon[1].z
for n = 1, #polygon do
local q = polygon[n]
minX = math.min(q.x, minX)
maxX = math.max(q.x, maxX)
minY = math.min(q.z, minY)
maxY = math.max(q.z, maxY)
end
if (p.x < minX or p.x > maxX or p.z < minY or p.z > maxY) then
return false
end
local i = 0;
local j = #polygon
for i = 1, #polygon do
if ((polygon[i].z > p.z) ~= (polygon[j].z > p.z) and
p.x < (polygon[j].x - polygon[i].x) * (p.z - polygon[i].z) / (polygon[j].z - polygon[i].z) + polygon[i].x ) then
isInside = not isInside
end
j = i
end
return isInside
end
end
local intersectRayRay do
function intersectRayRay(a1, a2, b1, b2)
local result;
local ua_t = (b2.x - b1.x) * (a1.z - b1.z) - (b2.z - b1.z) * (a1.x - b1.x)
local ub_t = (a2.x - a1.x) * (a1.z - b1.z) - (a2.z - a1.z) * (a1.x - b1.x)
local u_b = (b2.z - b1.z) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.z - a1.z)
if ( u_b ~= 0 ) then
local ua = ua_t / u_b
result = Vector3.new(
a1.x + ua * (a2.x - a1.x),
0,
a1.z + ua * (a2.z - a1.z)
)
else
if ( ua_t == 0 or ub_t == 0 ) then
result = {txt = "coincident"}
else
result = {txt = "parallel"}
end
end
return result
end
end
local raycast do
function raycast(node, dir, nodes, verts)
for i = 0.1, 500, 0.1 do
local pos = (CFrame.new(node.Start.Value, dir) * CFrame.new(0, 0, -i)).p
if not insidePolygon(verts, pos) then
return nil
end
for j, other in next, nodes do
if other ~= node then
local intersect = intersectRayRay(node.Start.Value, pos, other.Start.Value, other.End.Value)
if intersect then
if typeof(intersect) == "Vector3" then
return {
hit = other,
index = j,
pos = intersect
}
end
end
end
end
end
end
end
local Line do
function Line(pA, pB, col, se)
local s = (pA - pB).magnitude
local Line = Instance.new("Part", game.Workspace)
Line.Anchored, Line.CanCollide = true, false
Line.TopSurface, Line.BottomSurface = "Smooth", "Smooth"
Line.Color = col or Color3.new(1, 0, 0)
Line.Size = Vector3.new(se or 0.1, se or 0.1, s)
Line.CFrame = CFrame.new(pA, pB) * CFrame.new(0, 0, -s/2)
return Line
end
end
-- init
local points = game.Workspace.vertices:GetChildren()
table.sort(points, function (a, b)
return tonumber(a.Name) < tonumber(b.Name)
end)
local edges, vertices = { }, { }
table.foreach(points, function (i, v)
local nxt = i == #points and 1 or i + 1
edges[#edges + 1] = {
Start = {Value = v.Position * Vector3.new(1, 0, 1)};
End = {Value = points[nxt].Position * Vector3.new(1, 0, 1)};
}
vertices[#vertices + 1] = v.Position * Vector3.new(1, 0, 1)
-- debug
Line(edges[#edges].Start.Value, edges[#edges].End.Value, Color3.new(0, 1, 0), 0.125)
end)
for i, node in next, edges do
local dirs = {
up = node.Start.Value + Vector3.new( 0, 0, 200);
down = node.Start.Value + Vector3.new( 0, 0, -200);
right = node.Start.Value + Vector3.new( 200, 0, 0);
left = node.Start.Value + Vector3.new(-200, 0, 0);
}
for dir, vec in next, dirs do
local intersect = raycast(node, vec, edges, vertices)
if intersect then
-- debug
Line(node.Start.Value, intersect.pos)
end
end
end