Polygon generated from player created nodes

Now, I’m using code from this forum. Note that I have literally no clue how any of it actually works. But basically, the original code from the forum mentioned only makes triangles. So with small edits, I managed to figure out how to make so it can do multiple points, but it didn’t turn out how I wanted.

local Points = {}
local Color = BrickColor.new("Medium stone grey")
local Material = Enum.Material.SmoothPlastic
local Align = "Center"
local Thickness = 0.1
local Tris = {}

function spawnTrianglePart(col,mat)
	local P = Instance.new("WedgePart")
	P.Anchored = true
	P.Parent = workspace
	P.BrickColor = col
	P.Material = mat
	P.FrontSurface = Enum.SurfaceType.SmoothNoOutlines
	P.BackSurface = Enum.SurfaceType.SmoothNoOutlines
	P.LeftSurface = Enum.SurfaceType.SmoothNoOutlines
	P.RightSurface = Enum.SurfaceType.SmoothNoOutlines
	P.TopSurface = Enum.SurfaceType.SmoothNoOutlines
	P.BottomSurface = Enum.SurfaceType.SmoothNoOutlines
	return P
end	

function drawTriangle(a,b,c,n,ad)
	local len_AB = (b - a).magnitude
	local len_BC = (c - b).magnitude
	local len_CA = (a - c).magnitude

	if (len_AB > len_BC) and (len_AB > len_CA) then
		a,c = c,a
		b,c = c,b
	elseif (len_CA > len_AB) and (len_CA > len_BC) then
		a,b = b,a
		b,c = c,b
	end

	local dot = (a - b):Dot(c - b)
	local split = b + (c-b).unit*dot/(c - b).magnitude

	local xA = ad[3]
	local yA = (split - a).magnitude
	local zA = (split - b).magnitude

	local xB = ad[3]
	local yB = (split - a).magnitude
	local zB = (split - c).magnitude

	local diry = (a - split).unit
	local dirz = (c - split).unit
	local dirx = diry:Cross(dirz).unit

	local posA = split + diry*yA/2 - dirz*zA/2
	local posB = split + diry*yB/2 + dirz*zB/2

	local partA = spawnTrianglePart(ad[1],ad[2])
	partA.Name = "TrianglePart"
	partA.Size = Vector3.new(xA,math.min(yA,2048),math.min(zA,2048))
	local mA = Instance.new("SpecialMesh",partA)
	mA.MeshType = Enum.MeshType.Wedge
	mA.Scale = Vector3.new(xA,yA,zA)/partA.Size
	mA.Offset = Vector3.new(-n*(partA.Size.x-xA)/2,0,0)
	if mA.Scale == Vector3.new(1,1,1) then mA:Destroy() end
	partA.CFrame = CFrame.new(posA.x,posA.y,posA.z, dirx.x,diry.x,dirz.x, dirx.y,diry.y,dirz.y, dirx.z,diry.z,dirz.z)
	partA.CFrame = partA.CFrame:toWorldSpace(CFrame.new(n*math.max(.2,xA)/2,0,0))
	dirx = dirx * -1
	dirz = dirz * -1

	local partB = spawnTrianglePart(ad[1],ad[2])
	partB.Name = "TrianglePart"
	partB.Size = Vector3.new(xB,yB,zB)
	local mB = Instance.new("SpecialMesh",partB)
	mB.MeshType = Enum.MeshType.Wedge
	mB.Scale = Vector3.new(xB,math.min(yB,2048),math.min(zB,2048))/partB.Size
	mB.Offset = Vector3.new(n*(partB.Size.x-xB)/2,0,0)
	if mB.Scale == Vector3.new(1,1,1) then mB:Destroy() end
	partB.CFrame = CFrame.new(posB.x,posB.y,posB.z, dirx.x,diry.x,dirz.x, dirx.y,diry.y,dirz.y, dirx.z,diry.z,dirz.z)
	partB.CFrame = partB.CFrame:toWorldSpace(CFrame.new(-n*math.max(.2,xB)/2,0,0))
	
	return partA,partB
end

function CreateFloor:CreateTri(point)
	table.insert(Points,{point, point.Position})
	if (#Points >= 3) then
		local Pts = {{Points[1][1],Points[1][2]},{Points[2][1],Points[2][2]},{Points[3][1],Points[3][2]}}
		local Data = {Color,Material,Thickness}
		local Check = true
		for i,v in next,Tris do
			local Chcked1 = Pts[1][1] == v[2][1] or Pts[1][1] ==v [3][1] or Pts[1][1] == v[4][1]
			local Chcked2 = Pts[2][1] == v[2][1] or Pts[2][1] ==v [3][1] or Pts[2][1] == v[4][1]
			local Chcked3 = Pts[3][1] == v[2][1] or Pts[3][1] ==v [3][1] or Pts[3][1] == v[4][1]
			if (Chcked1 and Chcked2 and Chcked3) then
				for _,a in pairs(v[1]) do
					a:Destroy()
				end
				for _,a in pairs(v[5]) do
					a:disconnect()
				end
				table.remove(Tris,i)
				break
			end
		end		
			
		local N =- 1
		if (Align == "Center") then 
			N = 0 
		elseif (Align == "Inverted") then 
			N = 1 
		end
		local nTris={}
		
		nTris[1],nTris[2]=drawTriangle(Points[1][2],Points[2][2],Pts[3][2],N,Data)
		local nFunc={}
		table.insert(Tris,{nTris,Pts[1],Pts[2],Pts[3],nFunc,Data})
		for i=1,3 do
			table.insert(nFunc,Points[i][1].Changed:connect(function(property)
				if (property=="Position") then
					Pts[i][2] = Pts[i][1].Position
					for i,v in next,nTris do
						v:Destroy()
					end
					nTris[1],nTris[2]=drawTriangle(Pts[1][2],Pts[2][2],Pts[3][2],N,Data)
				end
			end))
		end
		--Points={}
		table.remove(Points, 1)
	end
end

Please note that I have read every article on this around the DevForums, plus numerous other articles online.

What I’m aiming for: Credit @Enqrypted


What I currently have
robloxapp201905041943328

As you can seen, my version is very ‘clunky’ and creates really weird shapes. I kind of know why it’s happening (basically I create a triangle after 3 nodes, and each node after just creates another triangle from the new node + previous 2 placed nodes) But I don’t know how to fix it

Correct, the code is selecting the last two nodes placed.

You want it to select the closest two nodes. That is loop through all the existing nodes and do (nodeA.Position - nodeB.position).magnitude then use the two nodes with lowest resulting value.

You’ve read all the forum posts… this one seems on point:
https://devforum.roblox.com/t/polygon-triangulation/274898

Ive tried that code before, looked really promising, but it constantly pulls up errors :confused::confused:

Problem with going thru all the nodes is keeping the code short and simple without cluttering it :confused:

I’d have to check node1 - node2, node1 - node3, node1 - node4, etc. and that could go on for 10-20 times over, and then repeat it all again but with node2

True, the approach I suggested loops through the nodes or points. Firstly though, I’m saying the answer to your primary question of how to achieve the result you’ve asked for is that you need the closest two nodes or points. Which algorithm or approach do you prefer or find to be more efficient for doing that? Up to you.

I’m interested in learning the most efficient solution to this problem too.

You haven’t stated explicit requirements … presumably a Player can click anywhere on any side of the existing set of nodes, so how do you find the closest to points for any click or tap position?

Here’s a thread about finding the closest enemy.

The generalized provided solution is cut down on the number of loops by doing some simple slice and dice pre-checks to whether you even need to check for new values, or at least minimize the number of value you need to loop through.

Still, generally speaking, we see a lot of code running through loops to do checks like this. You’re trying to use code you didn’t write to do a specific thing that you want to do. How inefficient can looping through 20 points only when a Player clicks or taps be?

1 Like