Look for Dead Ends

At the moment all 3 tile corner cases that are being matched by the algorithm are going to spawn a wall corner tile. For dead ends such as the image below, this does not look great. In this section, you will add a new function to find those dead ends and rotate the tile correctly.

Update MapBuilder API Script

You will need to add a few changes to the MapBuilder script. Some of the code is going to be refactored to make it easier to spawn extra tiles later on.

Update CheckForWallCorner Function

The CheckForWallCorner function will need a few changes. A new variable called extraTile will be created, and if there is a match, and that tileRow is not nil then the extraTile for this function will be a floor tile.

function MapBuilder.CheckForWallCorner(map, neighbors, row, col)
	local tileRow = nil
	local extraTile = nil
	local rotation = Rotation.New()

	if neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.EAST ~= nil and neighbors.SOUTH ~= nil then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 0
	elseif neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.WEST ~= nil and neighbors.SOUTH ~= nil then
		tileRow = TILES[MapBuilder.Type.WallCorner]
	 	rotation.z = 90
	elseif neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.NORTH ~= nil and neighbors.WEST ~= nil then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 180
	elseif neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.EAST ~= nil and neighbors.NORTH ~= nil  then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 270
	end

	if tileRow ~= nil then
		extraTile = TILES[MapBuilder.Type.Floor]
	end

	return tileRow, rotation, extraTile
end
Code language: Lua (lua)

Create CheckForDeadEnd Function

Create a new function called CheckForDeadEnd that will work very similar to the CheckForWallCorner function, the main only difference is the rotation of the tile will be 45 degree increments for the cardinal directions.

Tile Rotation

If the children of your tile have been rotated, then the rotation for the Z axis will be different for you. Change the rotation Z value until you find which values work for your tile.

function MapBuilder.CheckForDeadEnd(map, neighbors, row, col)
	local tileRow = nil
	local extraTile = nil
	local rotation = Rotation.New()

	if(neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall) then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 45
	elseif(neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall) then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 135
	elseif(neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall) then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = -135
	elseif(neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall) then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = -45
	end

	if tileRow ~= nil then
		extraTile = TILES[MapBuilder.Type.Floor]
	end

	return tileRow, rotation, extraTile
end
Code language: Lua (lua)

Update SpawnExtraTile Function

The SpawnExtraTile function will now take in the tile that will be spawned, and also do a check to see what type of tile it is. If it is the floor tile, then the rotation is reset and the scale is set to 1.

function MapBuilder.SpawnExtraTile(extraTile, params, container)
	if extraTile == nil then
		return
	end

	if MapBuilder.Type.Floor == extraTile.id then
		params.scale.z = 1
		params.rotation = Rotation.New()
	end

	container:SpawnSharedAsset(extraTile.tile, params)
end
Code language: Lua (lua)

Update Spawn Function

The Spawn function also needs updating so it can call the CheckForDeadEnd function. The order the checks are done is important, meaning that the dead end check should be done first, then the wall corner check, then finally the actual tile that matches the value from the map table.

function MapBuilder.Spawn(map, width, height, size, container)
	if not Environment.IsServer() then
		return
	end

	for row = 1, height do
		for col = 1, width do
			local tileRow, rotation, extraTile
			local neighbors = MapBuilder.GetNeighbors(map, row, col)

			tileRow, rotation, extraTile = MapBuilder.CheckForDeadEnd(map, neighbors, row, col)
			
			if tileRow == nil then
				tileRow, rotation, extraTile = MapBuilder.CheckForWallCorner(map, neighbors, row, col)
			end

			if tileRow == nil then
				tileRow = TILES[map[row][col]]
			end

			if tileRow ~= nil then
				local scale = Vector3.New(size / 100, size / 100, size / 100)

				if tileRow.floor then
					scale.z = 1
				end

				local x = -(row * size) + (height * size) / 2
				local y = (col * size) - (width * size) / 2

				local params = {

					scale = scale,
					position = Vector3.New(x, y, 0),
					rotation = rotation

				}

				container:SpawnSharedAsset(tileRow.tile, params)

				if extraTile ~= nil then
					MapBuilder.SpawnExtraTile(extraTile, params, container)
				end
			end
		end
	end
end
Code language: Lua (lua)

The MapBuilder Script

local ASCIIParser = require(script:GetCustomProperty("ASCIIParser"))
local TILES = require(script:GetCustomProperty("Tiles"))

local MapBuilder = {

	Type = {}

}

for key, row in pairs(TILES) do
	MapBuilder.Type[row.key] = row.id
end

function MapBuilder.Build(opts)
	local map, mapStr = ASCIIParser.BuildMap(opts.map, opts.width, opts.height)

	MapBuilder.Spawn(map, opts.width, opts.height, opts.size, opts.container)
end

function MapBuilder.GetTile(map, row, col)
	local foundRow = map[row]

	if foundRow then
		return foundRow[col]
	end

	return nil
end

function MapBuilder.GetNeighbors(map, row, column)
	return {

		NORTH = MapBuilder.GetTile(map, row - 1, column),
		SOUTH = MapBuilder.GetTile(map, row + 1, column),
		EAST = MapBuilder.GetTile(map, row, column + 1),
		WEST = MapBuilder.GetTile(map, row, column - 1)

	}
end

function MapBuilder.CheckForWallCorner(map, neighbors, row, col)
	local tileRow = nil
	local extraTile = nil
	local rotation = Rotation.New()

	if neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.EAST ~= nil and neighbors.SOUTH ~= nil then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 0
	elseif neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.WEST ~= nil and neighbors.SOUTH ~= nil then
		tileRow = TILES[MapBuilder.Type.WallCorner]
	 	rotation.z = 90
	elseif neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.NORTH ~= nil and neighbors.WEST ~= nil then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 180
	elseif neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST == MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall and neighbors.EAST ~= nil and neighbors.NORTH ~= nil  then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 270
	end

	if tileRow ~= nil then
		extraTile = TILES[MapBuilder.Type.Floor]
	end

	return tileRow, rotation, extraTile
end

function MapBuilder.CheckForDeadEnd(map, neighbors, row, col)
	local tileRow = nil
	local extraTile = nil
	local rotation = Rotation.New()

	if neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 45
	elseif neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = 135
	elseif neighbors.EAST == MapBuilder.Type.Wall and neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = -135
	elseif neighbors.SOUTH == MapBuilder.Type.Wall and neighbors.WEST == MapBuilder.Type.Wall and neighbors.NORTH == MapBuilder.Type.Wall and neighbors.EAST ~= MapBuilder.Type.Wall and map[row][col] ~= MapBuilder.Type.Wall then
		tileRow = TILES[MapBuilder.Type.WallCorner]
		rotation.z = -45
	end

	if tileRow ~= nil then
		extraTile = TILES[MapBuilder.Type.Floor]
	end

	return tileRow, rotation, extraTile
end

function MapBuilder.SpawnExtraTile(extraTile, params, container)
	if extraTile == nil then
		return
	end

	if MapBuilder.Type.Floor == extraTile.id then
		params.scale.z = 1
		params.rotation = Rotation.New()
	end

	container:SpawnSharedAsset(extraTile.tile, params)
end

function MapBuilder.Spawn(map, width, height, size, container)
	if not Environment.IsServer() then
		return
	end

	for row = 1, height do
		for col = 1, width do
			local tileRow, rotation, extraTile
			local neighbors = MapBuilder.GetNeighbors(map, row, col)

			tileRow, rotation, extraTile = MapBuilder.CheckForDeadEnd(map, neighbors, row, col)
			
			if tileRow == nil then
				tileRow, rotation, extraTile = MapBuilder.CheckForWallCorner(map, neighbors, row, col)
			end

			if tileRow == nil then
				tileRow = TILES[map[row][col]]
			end

			if tileRow ~= nil then
				local scale = Vector3.New(size / 100, size / 100, size / 100)

				if tileRow.floor then
					scale.z = 1
				end

				local x = -(row * size) + (height * size) / 2
				local y = (col * size) - (width * size) / 2

				local params = {

					scale = scale,
					position = Vector3.New(x, y, 0),
					rotation = rotation

				}

				container:SpawnSharedAsset(tileRow.tile, params)

				if extraTile ~= nil then
					MapBuilder.SpawnExtraTile(extraTile, params, container)
				end
			end
		end
	end
end

return MapBuilder
Code language: Lua (lua)

Test the Game

Test the game to make sure the wall corners and dead ends get a tile that is rotated correctly.

Scroll to Top