[HELP!] - How do I make this group of parts one single part?

Very weird, why doesn’t it work using that method? Wrong execution? Errors? Wrong algorithm?

1 Like

It’s because there a too many polygons.

Oh, makes sense, did you try greedy meshing? Very complex but looks like it’s the only method right now, it works by combining close parts together. Did a quick search to get you some resources and found this, very helpful and made by a Roblox programmer!

The thing is to convert it to one single mesh. I tried to take the whole model and substract it to one part. And then substract that part to another part to get the shape like a single mesh. That works but it takes too much time.

The reason why I want a group of parts as one single part is because I want to apply a texture and detect when a player is touching the model

No

Probably, I guess. I’m relying on the guy who said you could make it a mesh.

That’s where optimization is needed. Unfortunately, I don’t have any other ideas atm so, I can do nothing better than wishing you good luck.

Actually got a small idea, if your “shape” is pre-made then just create it before runtime and when needed, clone it and place it instead of that model thing.

That’s what I meant, I already got this idea before. Sorry…

And here, your union-ing the part and itself, maybe that’s what caused problems?

Ah, no worries, I never saw it and just got it to my mind so said it.

It’s not pre-made. What the script does it’s making a shape made out of vector coordinates which act as vertices. The script makes a grid and fills the space in the perimeter that forms the coordinates, then it creates part for joining every coordinate and then it creates a cylinder for each cooridnate.

This is the whole script without the union async:

local partstable = {}
local players = game.Players

local FillBase = game.ReplicatedStorage.FillBase
local CreateBase = game.ReplicatedStorage.CreateBase

-- Define las coordenadas vectoriales de los vértices del polígono
local vertices = {}
local InitialBase = {}

-- Define el tamaño de las partes que se usarán para rellenar el polígono
local partSize = 1.1

-- Crea una función auxiliar para determinar si un punto está dentro del polígono usando el algoritmo de ray casting
local function isInside(point, verts)
	local x = point.X
	local z = point.Z
	local inside = false
	local j = #verts
	for i = 1, #verts do
		local xi = verts[i].X
		local zi = verts[i].Z
		local xj = verts[j].X
		local zj = verts[j].Z
		if (zi > z) ~= (zj > z) and (x < (xj - xi) * (z - zi) / (zj - zi) + xi) then
			inside = not inside
		end
		j = i
	end
	return inside
end

-- Crea una función auxiliar para crear una parte con una posición y un color dados y añadirla a un modelo dado
local function createPart(position, color, model)
	local part = Instance.new("Part")
	part.Anchored = true -- Fija la parte en su lugar
	part.CanCollide = false
	part.Size = Vector3.new(partSize, 7, partSize) -- Establece el tamaño de la parte según la variable partSize
	part.Position = position -- Establece la posición de la parte según el argumento position
	part.Color = color -- Establece el color de la parte según el argumento color
	part.Parent = model -- Añade la parte al modelo según el argumento model
	part.Material = Enum.Material.SmoothPlastic
end

-- Crea una función auxiliar para rellenar un perímetro entre coordenadas vectoriales usando partes y luego unirlas para formar una sola unión con bordes suaves 
local function fillPerimeter(verticestable)
	-- Obtiene los límites del polígono en términos de coordenadas vectoriales
	local minX = math.huge
	local maxX = -math.huge
	local minZ = math.huge
	local maxZ = -math.huge

	for _, vertex in ipairs(verticestable) do
		local x = vertex.X
		local z = vertex.Z
		minX = math.min(minX, x)
		maxX = math.max(maxX, x)
		minZ = math.min(minZ, z)
		maxZ = math.max(maxZ, z)
	end

	-- Crea un nuevo modelo para contener las partes que forman el polígono
	local model = Instance.new("Model")
	model.Name = "Polygon"
	model.Parent = workspace

	-- Recorre todas las posiciones dentro de los límites y crea una parte si están dentro del polígono
	for x = minX, maxX, partSize do -- Incrementa x en incrementos de partSize
		for z = minZ, maxZ, partSize do -- Incrementa z en incrementos de partSize
			local position = Vector3.new(x + partSize / 2, 0, z + partSize / 2)

			if isInside(position,verticestable) then -- Comprueba si la posición está dentro del polígono usando la función isInside()
				createPart(position, Color3.new(1, 0.5, 0), model) -- Crea una parte con la posición y un color naranja y la añade al modelo 
			end
		end
	end

	local thickness = 1.5

	-- Loop through the coordinates and create a part for each edge
	for i = 1, #verticestable do
		-- Get the current coordinate and the next one in the loop or wrap around to the first one
		local coordinate1 = verticestable[i]
		local coordinate2 = verticestable[i + 1] or verticestable[1]

		-- Get the distance and direction between the two coordinates
		local distance = (coordinate2 - coordinate1).Magnitude
		local direction = (coordinate2 - coordinate1).Unit

		-- Create a new part with the given color and thickness
		local part = Instance.new("Part", model)
		part.Anchored = true
		part.CanCollide = false
		part.Color = Color3.new(1, 0.5, 0)
		part.Size = Vector3.new(thickness, 7, distance)
		part.Material = Enum.Material.SmoothPlastic

		-- Position and orient the part to match the edge
		part.CFrame = CFrame.new(coordinate1, coordinate2) * CFrame.new(0, 0, -distance / 2)
	end

	for i = 1, #verticestable do
		local point = verticestable[i]
		local cylinder = Instance.new("Part")
		cylinder.Shape = "Cylinder"
		cylinder.Anchored = true
		cylinder.CanCollide = false
		cylinder.Size = Vector3.new(7, thickness, thickness)
		cylinder.CFrame = CFrame.new(point) * CFrame.Angles(math.rad(0), math.rad(0), math.rad(90))
		cylinder.Parent = model
		cylinder.Color = Color3.new(1, 0.5, 0)
		cylinder.Material = Enum.Material.SmoothPlastic
	end

	for i, v in pairs(model:GetChildren()) do
		table.insert(partstable,v)
	end
	
end

FillBase.OnServerEvent:Connect(function(player)
	local trails = game.Workspace:WaitForChild(player.Name.."Trails")
	for i, v in pairs(trails:GetChildren()) do
		table.insert(vertices,Vector3.new(v.Position.X, 0, v.Position.Z))
	end

	fillPerimeter(vertices)
end)

CreateBase.OnServerEvent:Connect(function(player)
	local parts = game.Workspace:WaitForChild("InitialBase")
	parts:PivotTo(CFrame.new(math.random(-100,100),0,math.random(-100,100)))
	for i, v in pairs(parts:GetChildren()) do
		table.insert(InitialBase,Vector3.new(v.Position.X * 5, 0, v.Position.Z * 5))
	end

	fillPerimeter(InitialBase)
	player.Character.HumanoidRootPart.CFrame = parts:GetPivot() + Vector3.new(0, 2, 0)
end)

I can’t help you much sadly. I gave you all my ideas and.a

Are you sure you need it to be only 1 part? You could go through a loop through the group, and change the texture of every part in it. To detect if a player is touching the model, maybe use a raycast from the player downwards, detecting every part that the player touches. If the raycast hits a part, and that part’s parent is the group then you can know that the player is standing in the area. Just an idea, so I’m not sure if it will work for you.

Ok, I’ll see if it works, thanks for the idea