Help with combining parts in a 2D grid

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

Rather than simply creating one part for each space in my 2D grid of land, I was trying to implement a part generator for the grid which would combine the possible grid spaces and generate a single part for all of the spaces, which was a partial success. This is what I have achieved so far:


The brown parts are the parts the code is supposed to skip, and generate parts around them.

  1. What is the issue? Include screenshots / videos if possible!

I implemented it in 1D, how can I go about implementing it in 2D like so:

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I tried using the floodfill algorithm, breadth-first search, and this algorithm I found. Maybe they are the solutions but my implementation went horribly wrong.

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

My code that generates the parts in 1D:

function plot:draw()
	local function fill(sp, ep, s)
		local p = script[s]:Clone();
		p.Position = (sp + ep) / 2;
		p.Size = Vector3.new(math.abs(sp.X - ep.X), 0, math.abs(sp.Z - ep.Z)) + script[s].Size;
		if s == "Default" then	
			p.BrickColor = BrickColor.random();
		end
		p.Parent = workspace;
		return p;
	end

	for i, row in ipairs(self.land) do
		local lastPos = nil;
		local lastValidPos = nil;
		local lastState = nil;

		for j, l in ipairs(row) do
			local s = l:getState();

			if j == 1 then
				lastPos = l.position;
				lastValidPos = l.position;
				lastState = s;
				continue;
			end

			if s ~= lastState then
				fill(lastPos, lastValidPos, lastState);
				lastPos = l.position;
			end

			lastState = s;
			lastValidPos = l.position;
		end

		fill(lastPos, lastValidPos, lastState);
	end
end

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

Look into “greedy meshing”, there’s even a tutorial on it here on the devforums

Thank you!
I used @Dev_HDWC 's tutorial and it worked for me.
My code:

function plot:draw()
	local function fill(sp, ep, s)
		local p = script[s]:Clone();
		p.Position = (sp + ep) / 2;
		p.Size = Vector3.new(math.abs(sp.X - ep.X), 0, math.abs(sp.Z - ep.Z)) + script[s].Size;
		--if s == "Default" then	
		--	p.BrickColor = BrickColor.random();
		--end
		p.Parent = workspace;
		return p;
	end
	
	local visited = {};
	
	local function greedyMesh(x, y)
		
		local function getStr(x, y)
			return ("%i_%i"):format(x, y);
		end
		
		if x < 1 or x > self.grid.X or y < 1 or y > self.grid.Y then return; end
		
		local str = getStr(x, y);
		if table.find(visited, str) then return; end
		table.insert(visited, str);
		
		local endX = x;
		local endY = y;
		local state = self.land[x][y]:getState();
		
		while endX < self.grid.X do
			local newX = endX + 1;
			local newStr = getStr(newX, y);
			local s = self.land[newX][y]:getState()
			
			local canProceed = not table.find(visited, newStr) and s == state;
			if not canProceed then break; end
			
			table.insert(visited, newStr);
			state = s;
			endX = newX;
		end
		
		while endY < self.grid.Y do
			local newY = endY + 1;
			local rowCanProceed = true;
			
			for dx = x, endX do
				local canProceed = not table.find(visited, getStr(dx, newY)) and self.land[dx][newY]:getState() == state;
				if not canProceed then
					rowCanProceed  = false;
					break;
				end
			end
			
			if not rowCanProceed then break; end
	
			for dx = x, endX do
				table.insert(visited, getStr(dx, newY));
			end
			
			endY = newY;
		end
		
		fill(self.land[x][y].position, self.land[endX][endY].position, state);
	end
	
	for i = 1, self.grid.X do
		for j = 1, self.grid.Y do
			greedyMesh(i, j);
		end
	end
end

1 Like