Orienting tiles in a tile terrain generator not working

Hello, I am attempting to make a generator that generates a grid of tiles for a planet in a game I am working on. I have had significant issues having the tiles be oriented properly when adjacent to each other. I have tried having the orientation table of valid orientations of adjacent tiles directly determine the height and orientation of surrounding tiles, aswell as having the height remain similar and subsequently orienting adjacent generated tiles after the height is decided based on surrounding tiles.
Recently, I also tried generating line by line in which each tile would check the two other tiles near it to make a list of all valid spawned tiles, and yet issues still arise. I am unsure why the tiles are not orienting in the correct direction.

Edit: I am aware this may not be enough information to help solve this issue; I can post missing information if requested. The large table with the tiles includes the valid list of tiles and their valid orientations based on the direction the tile is being spawned in, the type of tile spawning the tile, the height, and various other factors.

Sample of current generation method (I have tried like 4 or more methods)

Current generation code:

Hello, I am attempting to make a generator that generates a grid of tiles for a planet in a game I am working on. I have had significant issues having the tiles be oriented properly when adjacent to each other. I have tried having the orientation table of valid orientations of adjacent tiles directly determine the height and orientation of surrounding tiles, aswell as having the height remain similar and subsequently orienting adjacent generated tiles after the height is decided based on surrounding tiles. 
Recently, I also tried generating line by line in which each tile would check the two other tiles near it to make a list of all valid spawned tiles, and yet issues still arise. I am unsure why the tiles are not orienting in the correct direction.

Sample of current generation method (I have tried like 4 or more methods)
![image|690x369](upload://r4VAom6czBh5pKjIOo4W5DgjyTe.jpeg)

Current generation code: 
local module = {}
local tIndex = require(game.ReplicatedStorage.TerrainIndex)
local StX, StZ = math.random(1, 80), math.random(1, 80) --Starting position of the generation

local function Round(Num)
	if Num >= math.floor(Num) + 0.5 then
		Num = math.ceil(Num)
	else 
		Num = math.floor(Num)
	end
	return Num
end

--when a part spawns rotated, compensate by having the opposite of the rotation added to the new part. 
--Also note that the orientation is the y orientation
--(NameOfTile)(HeightDifference+1) = {Orientation(s) when start orientation is 0}; selects a random orientation in the table.
--Spawner table contains placed tiles tables
local OrienTable = { --Front, Right, Back, Left Directions. List of valid orientations. ex: Flat0 == -1, Flat1 == +0, Flat2 == +1
	Flat = {
		["0"] = {Flat1 = {0, 90, 180, -90}, Corner1 = {180, 90}, Slant1 = {90}, Slant2 = {-90}, InvertedCorner1 = {90, 180}, Point2 = {0, 90, 180, -90}, SlantCorner2 = {180}}, --Infront of
		["90"] = {Flat1 = {0, 90, 180, -90}, Corner1 = {0, 90}, Slant1 = {0}, Slant2 = {180}, InvertedCorner1 = {90, 0}, Point2 = {0, 90, 180, -90}, SlantCorner2 = {180}},  --Right of
		["180"] = {Flat1 = {0, 90, 180, -90}, Corner1 = {0, -90}, Slant1 = {-90}, Slant2 = {90}, InvertedCorner1 = {-90, 0}, Point2 = {0, 90, 180, -90}, SlantCorner2 = {0}}, -- Back of
		["-90"] = {Flat1 = {0, 90, 180, -90}, Corner1 = {180, -90}, Slant1 = {180}, Slant2 = {0}, InvertedCorner1 = {-90, 180}, Point2 = {0, 90, 180, -90}, SlantCorner2 = {0}}}, -- Left of
	Corner = {
		["0"] = {Flat1 = {0, 90, 180, -90}, Corner1 = {180, 90}, Slant1 = {90}, Slant2 = {-90},InvertedCorner1 = {180, 90}, Point1 = {0, 90, 180, -90}, SlantCorner2 = {-90, 180}},
		["90"] = {Flat0 = {0, 90, 180, -90}, Corner0 = {0, 90}, Slant0 = {0}, Slant1 = {180}, InvertedCorner0 = {0, 90}, Point0 = {0, 90, 180, -90}, SlantCorner1 = {90, 180}},
		["180"] = {Flat0 = {0, 90, 180, -90}, Corner0 = {0, -90}, Slant0 = {-90}, Slant1 = {90}, InvertedCorner0 = {0, -90}, Point0 = {0, 90, 180, -90}, SlantCorner1 = {90, 0}},
		["-90"] = {Flat1 = {0, 90, 180, -90}, Corner1 = {180 -90}, Slant1 = {180}, Slant2 = {0}, InvertedCorner1 = {180, 90}, Point1 = {0, 90, 180, -90}, SlantCorner2 = {-90, 0}}},
	Slant = {
		["0"] = {Slant1 = {0}, InvertedCorner1 = {0}, SlantCorner1 = {0}},
		["90"] = {Flat0 = {0, 90, 180, -90}, Corner0 = {0, 90}, Slant0 = {0}, Slant1 = {180}, InvertedCorner0 = {0, 90}, Point1 = {0, 90, 180, -90}, SlantCorner1 = {0, 180}},
		["180"] = {Slant1 = {0}, InvertedCorner1 = {90}, SlantCorner1 = {-90}},
		["-90"] = {Flat1 = {0, 90, 180, -90}, Corner1 = {180, -90}, Slant1 = {180}, Slant2 = {0}, InvertedCorner1 = {180, -90}, Point2 = {0, 90, 180, -90}, SlantCorner2 = {0, -90}}},
	InvertedCorner = {
		["0"] = {Flat1 = {0, 90, 180, -90}, Corner2 = {0, -90}, Corner1 = {180, 90}, Slant2 = {-90}, Slant1 = {90}, InvertedCorner1 = {90, 180}, Point2 = {0, 90, 180, -90}, SlantCorner2 = {-90, 180}},
		["90"] = {Slant1 = {-90}, InvertedCorner1 = {-90}, SlantCorner1 = {-90}},
		["180"] = {Slant1 = {0}, InvertedCorner1 = {90}, SlantCorner1 = {-90}},
		["-90"] = {Flat1 = {0, 90, 180, -90}, Corner2 = {0, 90}, Corner1 = {180, -90}, Slant2 = {0}, Slant1 = {180}, InvertedCorner1 = {-90, 180}, Point2 = {0, 90, 180, -90}, SlantCorner2 = {-90, 0}}},
	Point = {
		["0"] = {Flat0 = {0, 90, 180, -90}, Corner0 = {180, 90}, Corner2 = {0, -90}, Slant1 = {-90}, Slant0 = {90}, InvertedCorner0 = {90, 180}, Point1 = {0, 90, 180, -90}, SlantCorner1 = {180, -90}},
		["90"] = {Flat0 = {0, 90, 180, -90}, Corner0 = {0, 90}, Corner2 = {180, -90}, Slant1 = {180}, Slant0 = {0}, InvertedCorner0 = {0, 90}, Point1 = {0, 90, 180, -90}, SlantCorner1 = {90, 180}},
		["180"] = {Flat0 = {0, 90, 180, -90}, Corner0 = {0, -90}, Corner2 = {180, 90}, Slant1 = {90}, Slant0 = {-90}, InvertedCorner0 = {0, -90}, Point1 = {0, 90, 180, -90}, SlantCorner1 = {0, 90}},
		["-90"] = {Flat0 = {0, 90, 180, -90}, Corner0 = {180, -90}, Corner2 = {0, 90}, Slant1 = {0}, Slant0 = {180}, InvertedCorner0 = {-90, 180}, Point1 = {0, 90, 180, -90}, SlantCorner1 = {-90, 0}}},
	SlantCorner = {--I accidentally did these in backwards order... whoops
		["0"] = {SlantCorner1 = {180, -90}, Point1 = {0, 90, 180, -90}, InvertedCorner0 = {90}, Slant0 = {90}, Slant1 = {-90}, Corner0 = {180, 90}, Flat0 = {0, 90, 180, -90}},
		["90"] = {SlantCorner1 = {180, 90}, Point1 = {0, 90, 180, -90}, InvertedCorner0 = {0}, Slant0 = {0}, Slant1 = {180}, Corner0 = {0, 90}, Flat0 = {0, 90, 180, -90}},
		["180"] = {SlantCorner1 = {-90}, InvertedCorner1 = {90}, Slant1 = {0}},
		["-90"] = {SlantCorner1 = {90}, InvertedCorner1 = {90}, Slant1 = {90}}}
}  --Table of valid tile orientations and configurations, utilizes tiles of heigh diffrence of 0-1 (also -1)

module.TGenNew = function(Biome)-- Select biome from TerrainIndex
	local Biome = tIndex[Biome]
	local dist = Biome.Scale
	local PlacedTiles = {}
	local TileFolder = Instance.new("Folder")
	TileFolder.Parent = game.Workspace
	TileFolder.Name = "GeneratedMap"
	for x = 1, 80 do PlacedTiles[x]  = {}--Sets up the matrix
		for z = 1, 80 do 
			PlacedTiles[x][z] = 0--AvailableTiles[math.random(1, #AvailableTiles)][math.random(1,4)]
		end
	end
	local a = {-1, 0, 1}
	local b = {-1, 1}
	local NewHeight2 = math.random(1,4)
	for v = 1, 80 do -- V = X, B = Z
		for b = 1, 80 do
			local function nextTile()-- Going right / 90° increases X, and going back/ 180° increases Z.
				local TileTypes = {"Flat", "Corner", "Slant", "InvertedCorner", "Point", "SlantCorner"}
				local TV
				local TB
				if v-1 ~= 0 and PlacedTiles[v-1] then
					TV = PlacedTiles[v-1][b]
				end
				if b-1 ~= 0 then
					TB = PlacedTiles[v][b-1]
				end
				if not TV and not TB then return game.Workspace.Tiles.BasicTiles.Flat[NewHeight2.."Flat"][NewHeight2.."Flat1"] end
				local TVType--Tile type of the last tile made in the X direction
				local TBType--Tile type of the last tile made in the Z direction
				local TVOrien --Orientation of the last tile made in the X direction
				local TBOrien  --Orientation of the last tile made in the Z direction
				local TVHeight --Height of the last tile made in the X direction
				local TBHeight--Height of the last tile made in the Z direction
				local NumberToSatisfy = 2
				local DV = 90--Base Direction that tiles are spawned in on the X-Axis
				local DB = 180--Base Direction that tiles are spawned in on the Z-Axis
				local GoodTiles = {}
				if TV then
					TVType = string.sub(TV.Name, 2, -2)
					TVOrien = TV.PrimaryPart.Orientation
					TVHeight = string.sub(TV.Name, 1, 1)
					DV += TVOrien.Y
					if DV >= 270 then DV = DV -360 elseif DV <-90 then DV += 360 end
					if DV == -90 then DV = "-90" else DV = tostring(DV) end
				end
				if TB then
					TBType = string.sub(TB.Name, 2, -2)
					TBOrien = TB.PrimaryPart.Orientation
					TBHeight = string.sub(TB.Name, 1, 1)
					DB += TBOrien.Y
					if DB >= 270 then DB = DB -360 elseif DB <-90 then DB += 360 end
					if DB == -90 then DB = "-90" else DB = tostring(DB) end
				end
				if not TV or not TB then NumberToSatisfy = 1 end
					for x, c in pairs({0, 1, 2}) do
						for z, d in pairs(TileTypes) do
							local Tester = d..c
							if NumberToSatisfy == 2 then
							if OrienTable[TVType][DV][Tester] and OrienTable[TBType][DB][Tester] and not (c-1+TVHeight < 0) and (not (c-1+TVHeight < 1 and d ~= "Flat")) and not (c-1+TVHeight > 5) and not (c-1+TBHeight < 0) and (not (c-1+TBHeight < 1 and d ~= "Flat")) and not (c-1+TBHeight > 5)  then 
								GoodTiles[Tester] = OrienTable[TVType][DV][Tester]
								end
							elseif TV then 
							if OrienTable[TVType][DV][Tester] and not (c-1+TVHeight < 0) and (not (c-1+TVHeight < 1 and d ~= "Flat")) and not (c-1+TVHeight > 5)  then
								GoodTiles[Tester] = OrienTable[TVType][DV][Tester]
								end
							elseif TB then 
							if OrienTable[TBType][DB][Tester] and not (c-1+TBHeight < 0) and (not (c-1+TBHeight < 1 and d ~= "Flat")) and not (c-1+TBHeight > 5)  then
								GoodTiles[Tester] = OrienTable[TBType][DB][Tester]
							end
							end
						end
					end
				local SelectedTile = {}
				local totalCount = 0
				for i, v in pairs(GoodTiles) do totalCount = totalCount + 1 end
				if totalCount == 0 then
					return game.Workspace.Tiles.BasicTiles.Flat[NewHeight2.."Flat"][NewHeight2.."Flat1"]
				end
				local ranTN = math.random(1, totalCount)
				local testCount2 = 0
				for i, v in pairs(GoodTiles) do 
					testCount2 = testCount2 + 1 
					if testCount2 == ranTN then
						SelectedTile["Tile"] = tostring((tonumber(string.sub(i, -1, -1))-1)+(TVHeight or TBHeight))..string.sub(i, 1, -2)
						SelectedTile["Orientation"] = v[math.random(1, #v)]
					end
				end
				local nTileFold = game.Workspace.Tiles.BasicTiles[string.sub(SelectedTile["Tile"], 2, -1)][SelectedTile["Tile"]]
				local which = math.random(1,4)
				local Tile, Ori = nTileFold[SelectedTile["Tile"]..which], SelectedTile["Orientation"]
				return Tile, Ori
			end
			local NewTile, NOri = nextTile()
			NewTile = NewTile:Clone()
			PlacedTiles[v][b] = NewTile
			NewTile.Parent = TileFolder
			NewTile:PivotTo(CFrame.new(Vector3.new((v)*100-4000, 10 ,(b)*100-4000))*CFrame.Angles(0, math.rad(NOri or 90), 0))
			PlacedTiles[v][b] = NewTile
			for i, v in pairs(PlacedTiles[v][b]:GetDescendants()) do
				if v.Name == "BASE" then
					v.Color = Biome.Base.Color
					v.Material = Biome.Base.Material
					if Biome.Base.MaterialVariant ~= nil then
						v.MaterialVariant = Biome.Base.MaterialVariant
					end
				elseif v.Name ~= "DepositSpawn" and v.Name ~= "FoliageSpawn" and v.Name ~= "EnemySpawn" then 
					v.Color = Biome.Top.Color
					v.Material = Biome.Top.Material
					if Biome.Top.MaterialVariant ~= nil then
						v.MaterialVariant = Biome.Top.MaterialVariant
					end
				end
			end
		end
	end
	
end

return module

1 Like

Are they at different heights? It looks like they are all at the same Y coordinate

The heights are changed via the tiles themselves, different tiles have different heights. These height differences can affect which tiles can be oriented to eachother. Due to pivot changes, setting them at the same Y coordinate works.

Image of all tiles, demonstrating height differences (In the background, the sets of 3-5 tiles are what we used to build the orientation table, which is supposed to dictate orientation.)

The function nextTile() is where the bulk of the logic involving orientation is done, and i suspect something with my tile logic is where the issue may be; perhaps just with the orientation processing or height logic is wrong. To add more notes, -90, 0, 90, and 180 refer to left, front, right, and back directions when the spawning tile is at a rotation of 0°. It is also supposed to compensate for the spawning tile rotation, however I am not 100% if it works.

I never did figure this out, but we simply made the tiles flat, with a small increase in values, and redid most of the code to make it look better. Additionally, slopes are added in between tiles with a low high change.

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