Fixing Z-Fighting in a randomly generated maze

I have created a script that randomly generates a maze from a center point in a perfectly cube-shaped formation.

Here’s the full script for anybody who wants to look. (It’s a server script)
(You can point out problems in my script if you also want to, but only after if the Z-Fighting gets solved.)

local storage = game:GetService("ReplicatedStorage")
local gameWorkspace = game:GetService("Workspace")
local replicatedFirst = game:GetService("ReplicatedFirst")

local walls = {
	storage.Maze.HorizentalLeft,
	storage.Maze.HorizentalRight,
	storage.Maze.VerticalLeft,
	storage.Maze.VerticalRight
}

local firstRandom = walls[math.random(#walls)]

local firstMazeSection = firstRandom:Clone()

firstMazeSection.Parent = gameWorkspace.Maze

local northX = 0
local northY = 0
local northZ = 0

local southX = 0
local southY = 0
local southZ = 0

local westX = 0
local westY = 0
local westZ = 0

local eastX = 0
local eastY = 0
local eastZ = 0

local northXD = 0
local northYD = 0
local northZD = 0

local southXD = 0
local southYD = 0
local southZD = 0

local westXD = 0
local westYD = 0
local westZD = 0

local eastXD = 0
local eastYD = 0
local eastZD = 0

--North and South

local cloneCounterNW = 0
local northWestPositions = {}
local flexibleCounterNW = 0

local cloneCounterNE = 0
local northEastPositions = {}
local flexibleCounterNE = 0

local cloneCounterSW = 0
local southWestPositions = {}
local flexibleCounterSW = 0

local cloneCounterSE = 0
local southEastPositions = {}
local flexibleCounterSE = 0

--East and West

local cloneCounterWN = 0
local westNorthPositions = {}
local flexibleCounterWN = 0

local cloneCounterWS = 0
local westSouthPositions = {}
local flexibleCounterWS = 0

local cloneCounterEN = 0
local eastNorthPositions = {}
local flexibleCounterEN = 0

local cloneCounterES = 0
local eastSouthPositions = {}
local flexibleCounterES = 0

local moveDistance = 24.5

local sections = {}

while cloneCounterNW <= 25 do
	task.wait()

	--Straight generations

	northX = northX +moveDistance

	local randomWallN = walls[math.random(#walls)]
	local cloneWallN = randomWallN:Clone()

	cloneWallN.Parent = game.Workspace.Maze
	cloneWallN:PivotTo(cloneWallN:GetPivot() +Vector3.new(northX, 0, 0))

	southX = southX +moveDistance

	local randomWallS = walls[math.random(#walls)]
	local cloneWallS = randomWallS:Clone()

	cloneWallS.Parent = game.Workspace.Maze
	cloneWallS:PivotTo(cloneWallS:GetPivot() -Vector3.new(southX, 0, 0))

	westZ = westZ +moveDistance

	local randomWallW = walls[math.random(#walls)]
	local cloneWallW = randomWallW:Clone()

	cloneWallW.Parent = game.Workspace.Maze
	cloneWallW:PivotTo(cloneWallW:GetPivot() -Vector3.new(0, 0, westZ))

	eastZ = eastZ +moveDistance

	local randomWallE = walls[math.random(#walls)]
	local cloneWallE = randomWallE:Clone()

	cloneWallE.Parent = game.Workspace.Maze
	cloneWallE:PivotTo(cloneWallE:GetPivot() +Vector3.new(0, 0, eastZ))

	--Diagonal generations

	northXD = northXD +moveDistance
	northZD = northZD +moveDistance

	local randomWallND = walls[math.random(#walls)]
	local cloneWallND = randomWallND:Clone()

	cloneWallND.Parent = game.Workspace.Maze
	cloneWallND:PivotTo(cloneWallND:GetPivot() +Vector3.new(northXD, 0, northZD))

	southXD = southXD +moveDistance
	southZD = southZD +moveDistance

	local randomWallSD = walls[math.random(#walls)]
	local cloneWallSD = randomWallSD:Clone()

	cloneWallSD.Parent = game.Workspace.Maze
	cloneWallSD:PivotTo(cloneWallSD:GetPivot() -Vector3.new(southXD, 0, southZD))

	westXD = westXD +moveDistance
	westZD = westZD -moveDistance

	local randomWallWD = walls[math.random(#walls)]
	local cloneWallWD = randomWallWD:Clone()

	cloneWallWD.Parent = game.Workspace.Maze
	cloneWallWD:PivotTo(cloneWallWD:GetPivot() +Vector3.new(westXD, 0, westZD))

	eastXD = eastXD -moveDistance
	eastZD = eastZD +moveDistance

	local randomWallED = walls[math.random(#walls)]
	local cloneWallED = randomWallED:Clone()

	cloneWallED.Parent = game.Workspace.Maze
	cloneWallED:PivotTo(cloneWallED:GetPivot() +Vector3.new(eastXD, 0, eastZD))

	--Filling in the gaps
	--Northwest

	if cloneCounterNW == 0 then
		cloneCounterNW = cloneCounterNW +1
	else
		repeat
			flexibleCounterNW  = flexibleCounterNW +moveDistance
			table.insert(northWestPositions, cloneCounterNW, cloneWallN.PrimaryPart.Position.Z 
				-flexibleCounterNW)

			local randomWallNW = walls[math.random(#walls)]
			local cloneWallNW = randomWallNW:Clone()

			cloneWallNW.Parent = game.Workspace.Maze
			cloneWallNW:PivotTo(cloneWallNW:GetPivot() +Vector3.new(math.abs(
				cloneWallN.PrimaryPart.Position.X -cloneWallNW.PrimaryPart.Position.X)), 0, 0)

			cloneWallNW:PivotTo(cloneWallNW:GetPivot() -Vector3.new(0, 0, 
				math.abs(flexibleCounterNW)))

		until flexibleCounterNW == cloneCounterNW *moveDistance

		for serial, value in pairs(northWestPositions) do
			table.remove(northWestPositions, serial)
		end


		flexibleCounterNW = 0
		cloneCounterNW = cloneCounterNW +1
	end

	--Northeast

	if cloneCounterNE == 0 then
		cloneCounterNE = cloneCounterNE +1
	else
		repeat
			flexibleCounterNE  = flexibleCounterNE +moveDistance
			table.insert(northEastPositions, cloneCounterNE, cloneWallN.PrimaryPart.Position.Z 
				-flexibleCounterNE)

			local randomWallNE = walls[math.random(#walls)]
			local cloneWallNE = randomWallNE:Clone()

			cloneWallNE.Parent = game.Workspace.Maze
			cloneWallNE:PivotTo(cloneWallNE:GetPivot() +Vector3.new(math.abs(
				cloneWallN.PrimaryPart.Position.X -cloneWallNE.PrimaryPart.Position.X)), 0, 0)

			cloneWallNE:PivotTo(cloneWallNE:GetPivot() +Vector3.new(0, 0, 
				math.abs(flexibleCounterNE)))

		until flexibleCounterNE == cloneCounterNE *moveDistance

		for serial, value in pairs(northEastPositions) do
			table.remove(northEastPositions, serial)
		end


		flexibleCounterNE = 0
		cloneCounterNE = cloneCounterNE +1
	end

	--Southwest

	if cloneCounterSW == 0 then
		cloneCounterSW = cloneCounterSW +1
	else
		repeat
			flexibleCounterSW  = flexibleCounterSW +moveDistance
			table.insert(southWestPositions, cloneCounterSW, cloneWallS.PrimaryPart.Position.Z 
				-flexibleCounterSW)

			local randomWallSW = walls[math.random(#walls)]
			local cloneWallSW = randomWallSW:Clone()

			cloneWallSW.Parent = game.Workspace.Maze
			cloneWallSW:PivotTo(cloneWallSW:GetPivot() -Vector3.new(math.abs(
				cloneWallS.PrimaryPart.Position.X -cloneWallSW.PrimaryPart.Position.X)), 0, 0)

			cloneWallSW:PivotTo(cloneWallSW:GetPivot() -Vector3.new(0, 0, 
				math.abs(flexibleCounterSW)))

		until flexibleCounterSW == cloneCounterSW *moveDistance

		for serial, value in pairs(southWestPositions) do
			table.remove(southWestPositions, serial)
		end


		flexibleCounterSW = 0
		cloneCounterSW = cloneCounterSW +1
	end

	--Southeast

	if cloneCounterSE == 0 then
		cloneCounterSE = cloneCounterSE +1
	else
		repeat
			flexibleCounterSE  = flexibleCounterSE +moveDistance
			table.insert(southEastPositions, cloneCounterSE, cloneWallS.PrimaryPart.Position.Z 
				-flexibleCounterSE)

			local randomWallSE = walls[math.random(#walls)]
			local cloneWallSE = randomWallSE:Clone()

			cloneWallSE.Parent = game.Workspace.Maze
			cloneWallSE:PivotTo(cloneWallSE:GetPivot() -Vector3.new(math.abs(
				cloneWallS.PrimaryPart.Position.X -cloneWallSE.PrimaryPart.Position.X)), 0, 0)

			cloneWallSE:PivotTo(cloneWallSE:GetPivot() +Vector3.new(0, 0, 
				math.abs(flexibleCounterSE)))

		until flexibleCounterSE == cloneCounterSE *moveDistance

		for serial, value in pairs(southEastPositions) do
			table.remove(southEastPositions, serial)
		end


		flexibleCounterSE = 0
		cloneCounterSE = cloneCounterSE +1
	end

	--Westnorth

	if cloneCounterWN == 0 then
		cloneCounterWN = cloneCounterWN +1
	else
		repeat
			flexibleCounterWN  = flexibleCounterWN +moveDistance
			table.insert(westNorthPositions, cloneCounterWN, cloneWallW.PrimaryPart.Position.X
				-flexibleCounterWN)

			local randomWallWN = walls[math.random(#walls)]
			local cloneWallWN = randomWallWN:Clone()

			cloneWallWN.Parent = game.Workspace.Maze
			cloneWallWN:PivotTo(cloneWallWN:GetPivot() -Vector3.new(0, 0, 
				math.abs(cloneWallW.PrimaryPart.Position.Z -cloneWallWN.PrimaryPart.Position.Z)))

			cloneWallWN:PivotTo(cloneWallWN:GetPivot() +Vector3.new(math.abs(
				flexibleCounterWN)), 0, 0)

		until flexibleCounterWN == cloneCounterWN *moveDistance

		for serial, value in pairs(westNorthPositions) do
			table.remove(westNorthPositions, serial)
		end


		flexibleCounterWN = 0
		cloneCounterWN = cloneCounterWN +1
	end

	--Westsouth

	if cloneCounterWS == 0 then
		cloneCounterWS = cloneCounterWS +1
	else
		repeat
			flexibleCounterWS  = flexibleCounterWS +moveDistance
			table.insert(westSouthPositions, cloneCounterWS, cloneWallW.PrimaryPart.Position.X
				-flexibleCounterWS)

			local randomWallWS = walls[math.random(#walls)]
			local cloneWallWS = randomWallWS:Clone()

			cloneWallWS.Parent = game.Workspace.Maze
			cloneWallWS:PivotTo(cloneWallWS:GetPivot() -Vector3.new(0, 0, 
				math.abs(cloneWallW.PrimaryPart.Position.Z -cloneWallWS.PrimaryPart.Position.Z)))

			cloneWallWS:PivotTo(cloneWallWS:GetPivot() -Vector3.new(math.abs(
				flexibleCounterWS)), 0, 0)

		until flexibleCounterWS == cloneCounterWS *moveDistance

		for serial, value in pairs(westSouthPositions) do
			table.remove(westSouthPositions, serial)
		end


		flexibleCounterWS = 0
		cloneCounterWS = cloneCounterWS +1
	end

	--Eastnorth

	if cloneCounterEN == 0 then
		cloneCounterEN = cloneCounterEN +1
	else
		repeat
			flexibleCounterEN  = flexibleCounterEN +moveDistance
			table.insert(eastNorthPositions, cloneCounterEN, cloneWallE.PrimaryPart.Position.X
				-flexibleCounterEN)

			local randomWallEN = walls[math.random(#walls)]
			local cloneWallEN = randomWallEN:Clone()

			cloneWallEN.Parent = game.Workspace.Maze
			cloneWallEN:PivotTo(cloneWallEN:GetPivot() +Vector3.new(0, 0, 
				math.abs(cloneWallE.PrimaryPart.Position.Z -cloneWallEN.PrimaryPart.Position.Z)))

			cloneWallEN:PivotTo(cloneWallEN:GetPivot() +Vector3.new(math.abs(
				flexibleCounterEN)), 0, 0)

		until flexibleCounterEN == cloneCounterEN *moveDistance

		for serial, value in pairs(eastNorthPositions) do
			table.remove(eastNorthPositions, serial)
		end


		flexibleCounterEN = 0
		cloneCounterEN = cloneCounterEN +1
	end

	--Eastsouth

	if cloneCounterES == 0 then
		cloneCounterES = cloneCounterES +1
	else
		repeat
			flexibleCounterES  = flexibleCounterES +moveDistance
			table.insert(eastSouthPositions, cloneCounterES, cloneWallE.PrimaryPart.Position.X
				-flexibleCounterES)

			local randomWallES = walls[math.random(#walls)]
			local cloneWallES = randomWallES:Clone()

			cloneWallES.Parent = game.Workspace.Maze
			cloneWallES:PivotTo(cloneWallES:GetPivot() +Vector3.new(0, 0, 
				math.abs(cloneWallE.PrimaryPart.Position.Z -cloneWallES.PrimaryPart.Position.Z)))

			cloneWallES:PivotTo(cloneWallES:GetPivot() -Vector3.new(math.abs(
				flexibleCounterES)), 0, 0)

		until flexibleCounterES == cloneCounterES *moveDistance

		for serial, value in pairs(eastSouthPositions) do
			table.remove(eastSouthPositions, serial)
		end


		flexibleCounterES = 0
		cloneCounterES = cloneCounterES +1
	end
end

storage.Maze.GeneratedMaze:FireClient()

Now, when these walls get generated I have to make the walls merge with each other so that they form a seamless array of walls.
But of course, this would obviously cause Z-Fighting, which is recognized as an event that happens when two textures are “fighting” because they perfectly overlap. I want to create a randomly generated maze that does not cause intense lag or show Z-Fighting.

Examples of the Z-Fighting that occurs:



Now, as I don’t want the maze to cause intense lag, unions or negative parts are out of the question, as I have already tried them and almost received the crashing of my Roblox Studio, and as they are known to be very laggy in the first place. I have tried offsetting, but changing the generated walls’ position by even a small margin like 0.001 studs or giving the types of walls different offsets only solves some of the Z-Fighting and not all of it. I have went through many Roblox Wiki pages and Dev forum posts and haven’t found a viable solution yet.

Note that I want to avoid using 3-D software but if the problem can’t be solved by scripting, I will if I have to.

(Also would this be more of a Scripting Support topic or the people over there would be able to help me more? Tell me if it is.)

Thanks for reading.

2 Likes

I think someone was having a similar issue except it was with the ceilings and floors of a backroom generator. I believe they solved their problem by using a material instead of a texture. I’ll link the post when I find it.

perhaps math.random most of the generated parts to some extent that makes it not noticable?

Thank you!
I WAS looking for some kind of special part that didn’t cause Z-Fighting, and this was the exact thing I was looking for.
I tested this in Roblox Studio and it does indeed stop the visual glitching.
Thank you again.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.