Create ASCIIEditor API

You will create an API that will contain all the functions for the editor. This script will handle dynamically creating the grid and tile controls.

  1. Create a new script called ASCIIEditor and move it to the Editor folder under My Scripts in the Project Content window.
  2. Add the Tiles data table as a custom property called Tiles.
  3. Add the Control Tile template as a custom property called ControlTile.
  4. Add the Map Tile template as a custom property called MapTile

Edit ASCIIEditor Script

Open up the ASCIIEditor script and add the following variables so you have references to the properties. The ASCIIEditor table will contain some properties that will be set throughout the API by various functions.

local TILES = require(script:GetCustomProperty("Tiles"))
local CONTROL_TILE = script:GetCustomProperty("ControlTile")
local MAP_TILE = script:GetCustomProperty("MapTile")

local ASCIIEditor = {

	activeControl = nil,
	startingColor = nil,
	startingId = nil,
	opts = {}

}
Code language: Lua (lua)

Create Build Function

Create a function called Build. This function will enable the cursor, the opts table is set to the parameter opts that is sent into the Build function. At the same time, the clickedEvent is connected for all the various UI buttons.

function ASCIIEditor.Build(opts)
	UI.SetCursorVisible(true)
	UI.SetCanCursorInteractWithUI(true)

	ASCIIEditor.opts = opts

	opts.INCREASE_WIDTH.clickedEvent:Connect(ASCIIEditor.ResizeGrid, 1, 0)
	opts.DECREASE_WIDTH.clickedEvent:Connect(ASCIIEditor.ResizeGrid, -1, 0)
	opts.INCREASE_HEIGHT.clickedEvent:Connect(ASCIIEditor.ResizeGrid, 0, 1)
	opts.DECREASE_HEIGHT.clickedEvent:Connect(ASCIIEditor.ResizeGrid, 0, -1)

	opts.EXPORT_ASCII.clickedEvent:Connect(ASCIIEditor.BuildASCIIMap)

	ASCIIEditor.CreateControls()
	ASCIIEditor.CreateGrid()
end
Code language: Lua (lua)

Create OnTileHover Function

Create a function called OnTileHover. This function will change the button color when the mouse is hovered over a grid tile. At the same time it will check to see if the action Fast Color is being held down, if it is, it will automatically set the background and custom property of the tile that was hovered over. This makes it easier to color tiles.

function ASCIIEditor.OnTileHover(button)
	button:SetButtonColor(Color.WHITE)

	if Input.IsActionHeld(Game.GetLocalPlayer(), "Fast Color") then
		button:FindChildByName("Background"):SetColor(ASCIIEditor.activeControl:FindChildByName("Background"):GetColor())
		button:SetCustomProperty("id", ASCIIEditor.activeControl:GetCustomProperty("id"))
	end
end
Code language: Lua (lua)

Create OnTileUnhovered Function

Create a function called OnTileUnhovered. This function will revert the button color to its original color when the mouse is unhovered.

function ASCIIEditor.OnTileUnhovered(button)
	button:SetButtonColor(Color.BLACK)
end
Code language: Lua (lua)

Create OnTileClicked Function

Create a function called OnTileClicked. This function will change the background color of the button and set the custom property when it has been clicked on.

function ASCIIEditor.OnTileClicked(button)
	button:FindChildByName("Background"):SetColor(ASCIIEditor.activeControl:FindChildByName("Background"):GetColor())
	button:SetCustomProperty("id", ASCIIEditor.activeControl:GetCustomProperty("id"))
end
Code language: Lua (lua)

Create CreateGrid Function

Create a function called CreateGrid. This function will create the grid with all the tiles. Each tile will be set to the startingColor value, which will normally be the floor tile color. At the same time, the dynamic property id is set to the startingId.

The function also handles setting up the buttons events for when the mouse hovers and clicks on a tile.

To keep the grid centered in the UI, the function sets the width and height based on how many tiles there are. Each tile is 50 x 50, but too many tiles could cause the container to overflow, so a bit of checking is done to make sure the map is no more than 900 in height, if it is, then the scroll panel will be used.

function ASCIIEditor.CreateGrid()
	for row = 1, ASCIIEditor.opts.HEIGHT do
		local x_offset = 0
		local y_offset = (row - 1) * 50

		for col = 1, ASCIIEditor.opts.WIDTH do
			local tile = World.SpawnAsset(MAP_TILE)

			if ASCIIEditor.startingColor ~= nil then
				tile:FindChildByName("Background"):SetColor(ASCIIEditor.startingColor)
			end

			tile:SetCustomProperty("id", ASCIIEditor.startingId)

			tile.hoveredEvent:Connect(ASCIIEditor.OnTileHover)
			tile.unhoveredEvent:Connect(ASCIIEditor.OnTileUnhovered)
			tile.clickedEvent:Connect(ASCIIEditor.OnTileClicked)

			tile.parent = ASCIIEditor.opts.MAP_SCROLL_PANEL
			tile.y = y_offset
			tile.x = x_offset

			x_offset = x_offset + 50
		end
	end

	ASCIIEditor.opts.MAP.width = (ASCIIEditor.opts.WIDTH * 50) + 5
	ASCIIEditor.opts.MAP.height = math.min(900, (ASCIIEditor.opts.HEIGHT * 50) + 5)
end
Code language: Lua (lua)

Create OnControlTileClicked Function

Create a function called OnControlTileClicked. This function will detect when a tile has been clicked on. If the current tile is the same as the last activeControl tile, then no change is needed. Otherwise, the color is changed, and the activeControl is reverted to the default color. The current button is then set as the activeControl.

function ASCIIEditor.OnControlTileClicked(button)
	if button == ASCIIEditor.activeControl then
		return
	end

	ASCIIEditor.activeControl:SetButtonColor(Color.BLACK)
	button:SetButtonColor(Color.WHITE)
	ASCIIEditor.activeControl = button
end
Code language: Lua (lua)

Create CreateControls Function

Create a function called CreateControls. This function will dynamically create the controls in the UI by looping over the Tiles data table to find which tiles are valid. Valid tiles from the data table are tiles that are not below 0. The color of each control is also set by using the color from the row in the data table. Each tile has a dynamic property called id that is set to the id from the row in the data table.

The function will also look for the Floor tile and make this the activeControl by default.

function ASCIIEditor.CreateControls()
	local y_offset = 0
	local count = 0

	for key, row in pairs(TILES) do
		local num = tonumber(row.id)
	
		if num == nil or num >= 0 then
			local tile = World.SpawnAsset(CONTROL_TILE)
			
			tile.parent = ASCIIEditor.opts.CONTROLS_SCROLL_PANEL
			tile:FindChildByName("Text").text = string.format("%s (%s)", row.key, row.id)
			tile.y = y_offset

			tile:FindChildByName("Background"):SetColor(row.color)

			if row.key == "Floor" then
				ASCIIEditor.activeControl = tile
				ASCIIEditor.startingId = row.id
				ASCIIEditor.startingColor = row.color
				tile:SetButtonColor(Color.WHITE)
			end

			tile:SetCustomProperty("id", row.id)
			tile.clickedEvent:Connect(ASCIIEditor.OnControlTileClicked)

			y_offset = y_offset + 52
			count = count + 1
		end
	end

	ASCIIEditor.opts.CONTROLS.height = math.min(600, (count * 50) + 5)
end
Code language: Lua (lua)

Create BuildASCIIMap Function

Create a function called BuildASCIIMap that will loop through all of the children of the scroll panel and build up the ASCII string that will get printed to the Event Log. You can then take this string and put it into the GenerateMap script to play the new map.

function ASCIIEditor.BuildASCIIMap()
	local children = ASCIIEditor.opts.MAP_SCROLL_PANEL:GetChildren()
	local mapStr = ""

	for index, child in ipairs(children) do
		mapStr = mapStr .. child:GetCustomProperty("id")

		if(index % ASCIIEditor.opts.WIDTH == 0) then
			mapStr = mapStr .. "\n"
		end
	end

	print(mapStr)
end
Code language: Lua (lua)

Create ClearGrid Function

Create a new function called ClearGrid. This function will destroy all the grid tiles by looping through all the children in the scroll panel.

function ASCIIEditor.ClearGrid()
	local children = ASCIIEditor.opts.MAP_SCROLL_PANEL:GetChildren()

	for index, child in ipairs(children) do
		child:Destroy()
	end
end
Code language: Lua (lua)

Create UpdateGridWidthHeightText Function

Create a new function called UpdateGridWidthHeightText. This function will update the width and height of the grid so you can see what it is currently set to.

function ASCIIEditor.UpdateGridWidthHeightText()
	ASCIIEditor.opts.WIDTH_TEXT.text = string.format("Map Width (%s)", ASCIIEditor.opts.WIDTH)
	ASCIIEditor.opts.HEIGHT_TEXT.text = string.format("Map Height (%s)", ASCIIEditor.opts.HEIGHT)
end
Code language: Lua (lua)

Create ResizeGrid Function

Create a new function called ResizeGrid that will either increase or decrease the grid width. This function is destructive, meaning that any current tiles set in the grid will be cleared.

function ASCIIEditor.ResizeGrid(button, w, h)
	ASCIIEditor.opts.WIDTH = ASCIIEditor.opts.WIDTH + w
	ASCIIEditor.opts.HEIGHT = ASCIIEditor.opts.HEIGHT + h

	ASCIIEditor.UpdateGridWidthHeightText()

	ASCIIEditor.ClearGrid()
	ASCIIEditor.CreateGrid()
end
Code language: Lua (lua)

The ASCIIEditor Script

local TILES = require(script:GetCustomProperty("Tiles"))
local CONTROL_TILE = script:GetCustomProperty("ControlTile")
local MAP_TILE = script:GetCustomProperty("MapTile")

local ASCIIEditor = {

	activeControl = nil,
	startingColor = nil,
	startingId = nil,
	opts = {}

}

function ASCIIEditor.Build(opts)
	UI.SetCursorVisible(true)
	UI.SetCanCursorInteractWithUI(true)

	ASCIIEditor.opts = opts

	opts.INCREASE_WIDTH.clickedEvent:Connect(ASCIIEditor.ResizeGrid, 1, 0)
	opts.DECREASE_WIDTH.clickedEvent:Connect(ASCIIEditor.ResizeGrid, -1, 0)
	opts.INCREASE_HEIGHT.clickedEvent:Connect(ASCIIEditor.ResizeGrid, 0, 1)
	opts.DECREASE_HEIGHT.clickedEvent:Connect(ASCIIEditor.ResizeGrid, 0, -1)

	opts.EXPORT_ASCII.clickedEvent:Connect(ASCIIEditor.BuildASCIIMap)

	ASCIIEditor.CreateControls()
	ASCIIEditor.CreateGrid()
end

function ASCIIEditor.OnTileHover(button)
	button:SetButtonColor(Color.WHITE)

	if Input.IsActionHeld(Game.GetLocalPlayer(), "Fast Color") then
		button:FindChildByName("Background"):SetColor(ASCIIEditor.activeControl:FindChildByName("Background"):GetColor())
		button:SetCustomProperty("id", ASCIIEditor.activeControl:GetCustomProperty("id"))
	end
end

function ASCIIEditor.OnTileUnhovered(button)
	button:SetButtonColor(Color.BLACK)
end

function ASCIIEditor.OnTileClicked(button)
	button:FindChildByName("Background"):SetColor(ASCIIEditor.activeControl:FindChildByName("Background"):GetColor())
	button:SetCustomProperty("id", ASCIIEditor.activeControl:GetCustomProperty("id"))
end

function ASCIIEditor.CreateGrid()
	for row = 1, ASCIIEditor.opts.HEIGHT do
		local x_offset = 0
		local y_offset = (row - 1) * 50

		for col = 1, ASCIIEditor.opts.WIDTH do
			local tile = World.SpawnAsset(MAP_TILE)

			if ASCIIEditor.startingColor ~= nil then
				tile:FindChildByName("Background"):SetColor(ASCIIEditor.startingColor)
			end

			tile:SetCustomProperty("id", ASCIIEditor.startingId)

			tile.hoveredEvent:Connect(ASCIIEditor.OnTileHover)
			tile.unhoveredEvent:Connect(ASCIIEditor.OnTileUnhovered)
			tile.clickedEvent:Connect(ASCIIEditor.OnTileClicked)

			tile.parent = ASCIIEditor.opts.MAP_SCROLL_PANEL
			tile.y = y_offset
			tile.x = x_offset

			x_offset = x_offset + 50
		end
	end

	ASCIIEditor.opts.MAP.width = (ASCIIEditor.opts.WIDTH * 50) + 5
	ASCIIEditor.opts.MAP.height = math.min(900, (ASCIIEditor.opts.HEIGHT * 50) + 5)
end

function ASCIIEditor.OnControlTileClicked(button)
	if button == ASCIIEditor.activeControl then
		return
	end

	ASCIIEditor.activeControl:SetButtonColor(Color.BLACK)
	button:SetButtonColor(Color.WHITE)
	ASCIIEditor.activeControl = button
end

function ASCIIEditor.CreateControls()
	local y_offset = 0
	local count = 0

	for key, row in pairs(TILES) do
		local num = tonumber(row.id)
	
		if num == nil or num >= 0 then
			local tile = World.SpawnAsset(CONTROL_TILE)
			
			tile.parent = ASCIIEditor.opts.CONTROLS_SCROLL_PANEL
			tile:FindChildByName("Text").text = string.format("%s (%s)", row.key, row.id)
			tile.y = y_offset

			tile:FindChildByName("Background"):SetColor(row.color)

			if row.key == "Floor" then
				ASCIIEditor.activeControl = tile
				ASCIIEditor.startingId = row.id
				ASCIIEditor.startingColor = row.color
				tile:SetButtonColor(Color.WHITE)
			end

			tile:SetCustomProperty("id", row.id)
			tile.clickedEvent:Connect(ASCIIEditor.OnControlTileClicked)

			y_offset = y_offset + 52
			count = count + 1
		end
	end

	ASCIIEditor.opts.CONTROLS.height = math.min(600, (count * 50) + 5)
end

function ASCIIEditor.BuildASCIIMap()
	local children = ASCIIEditor.opts.MAP_SCROLL_PANEL:GetChildren()
	local mapStr = ""

	for index, child in ipairs(children) do
		mapStr = mapStr .. child:GetCustomProperty("id")

		if(index % ASCIIEditor.opts.WIDTH == 0) then
			mapStr = mapStr .. "\n"
		end
	end

	print(mapStr)
end

function ASCIIEditor.ClearGrid()
	local children = ASCIIEditor.opts.MAP_SCROLL_PANEL:GetChildren()

	for index, child in ipairs(children) do
		child:Destroy()
	end
end

function ASCIIEditor.UpdateGridWidthHeightText()
	ASCIIEditor.opts.WIDTH_TEXT.text = string.format("Map Width (%s)", ASCIIEditor.opts.WIDTH)
	ASCIIEditor.opts.HEIGHT_TEXT.text = string.format("Map Height (%s)", ASCIIEditor.opts.HEIGHT)
end

function ASCIIEditor.ResizeGrid(button, w, h)
	ASCIIEditor.opts.WIDTH = ASCIIEditor.opts.WIDTH + w
	ASCIIEditor.opts.HEIGHT = ASCIIEditor.opts.HEIGHT + h

	ASCIIEditor.UpdateGridWidthHeightText()

	ASCIIEditor.ClearGrid()
	ASCIIEditor.CreateGrid()
end

return ASCIIEditor
Code language: Lua (lua)
Scroll to Top