Advanced Dance Floor [mad city]

Yes, I would think that using another 2D array, or even the same one for color maps would probably fit this project best.

Yes! We can modify the script to contain a new table for the ColorMap, then initialize the ColorMap along with the grid in the CreateGrid() function, then add another function to apply the ColorMap to the grid like so:

local FloorTiles = {} -- 2D array containing each tile
local ColorMap = {} -- 2D array containing each tile's color.

-- Note: It is probably best to simulate this on the client and dynamically load and unload it
-- to avoid massive server lag.
-- This is server sided just for testing purposes.

local function ApplyColorMap()
	for y = 1, #FloorTiles, 1 do
		for x = 1, #FloorTiles[y] do
			local part = FloorTiles[y][x]

			if ColorMap[y][x] then
				part.Color = ColorMap[y][x]
			end
		end
	end
end

local function CreateFloor(position:Vector3, tile_size:Vector3, padding:Vector2, grid_size:Vector2)
	FloorTiles = {}
	
	local current_position = position
	
	-- Y column
	for y = 1, grid_size.X, 1 do
		FloorTiles[y] = {}
		ColorMap[y] = {}
		
		-- X column
		for x = 1, grid_size.Y, 1 do
			local new_tile = Instance.new("Part")
			new_tile.Position = current_position
			new_tile.Size = tile_size
			new_tile.Anchored = true
			new_tile.CanCollide = false
			new_tile.Parent = DanceFloor
			
			-- Setup position for next tile
			current_position += Vector3.new(tile_size.X, 0, 0) + Vector3.new(padding.X, 0, 0)
			
			FloorTiles[y][x] = new_tile
			ColorMap[y][x] = Color3.new(1, 1, 1) -- Initialize to white, or whatever color you like.
		end 
		
		-- Reset position X at the end of each X column
		local old_z, old_y = current_position.Z, current_position.Y
		current_position = Vector3.new(position.X, old_y, old_z)
		
		-- Shift position over for next X column
		current_position += Vector3.new(0, 0, tile_size.Z) + Vector3.new(0, 0, padding.Y)
	end
	
	ApplyColorMap()
end

So, I also got the model, and dug into it. It appears that the person in the video is using perlin noise to create the waving gradient effects.

I modified the script a little to include a demo of possible perlin noise effects.

local RunService = game:GetService("RunService")

local DanceFloor = game:GetService("Workspace"):WaitForChild("DanceFloor")

local FloorTiles = {} -- 2D array containing each tile
local ColorMap = {} -- 2D array containing each tile's color.

-- What the table looks like:
--[[ 4x4 dance floor example
	{
		[1] = {[1] = Part; [2] = Part; [3] = Part; [4] = Part;};
		[2] = {[1] = Part; [2] = Part; [3] = Part; [4] = Part;};
		[3] = {[1] = Part; [2] = Part; [3] = Part; [4] = Part;};
		[4] = {[1] = Part; [2] = Part; [3] = Part; [4] = Part;};
	}
]]

-- Note: It is probably best to simulate this on the client and dynamically load and unload it
-- to avoid massive server lag.
-- This is server sided just for testing purposes.

local function ApplyColorMap()
	for y = 1, #FloorTiles, 1 do
		for x = 1, #FloorTiles[y] do
			local part = FloorTiles[y][x]

			if ColorMap[y][x] then
				part.Color = ColorMap[y][x]
			end
		end
	end
end

local function CreateFloor(position:Vector3, tile_size:Vector3, padding:Vector2, grid_size:Vector2)
	FloorTiles = {}
	
	local current_position = position
	
	-- Y column
	for y = 1, grid_size.X, 1 do
		FloorTiles[y] = {}
		ColorMap[y] = {}
		
		-- X column
		for x = 1, grid_size.Y, 1 do
			local new_tile = Instance.new("Part")
			new_tile.Position = current_position
			new_tile.Size = tile_size
			new_tile.Anchored = true
			new_tile.CanCollide = false
			new_tile.CastShadow = false -- Optimizations
			new_tile.Parent = DanceFloor
			
			-- Setup position for next tile
			current_position += Vector3.new(tile_size.X, 0, 0) + Vector3.new(padding.X, 0, 0)
			
			FloorTiles[y][x] = new_tile
			ColorMap[y][x] = Color3.new(1, 1, 1) -- Initialize to white, or whatever color you like.
		end 
		
		-- Reset position X at the end of each X column
		local old_z, old_y = current_position.Z, current_position.Y
		current_position = Vector3.new(position.X, old_y, old_z)
		
		-- Shift position over for next X column
		current_position += Vector3.new(0, 0, tile_size.Z) + Vector3.new(0, 0, padding.Y)
	end
	
	ApplyColorMap()
end

local function PerlinNoiseTest(color, offset)
	for y = 1, #ColorMap, 1 do
		for x = 1, #ColorMap[y] do
			local noise = math.noise((x / 10) + offset, (y / 10) + offset) * 0.5
			-- noise returns a value between -0.5 and 0.5. The values are
			-- procedurally generated.
			ColorMap[y][x] = Color3.new(color.R + noise, color.G + noise, color.B + noise)
		end
	end
end


-- Create dance floor
CreateFloor(
	Vector3.new(0, 1, 0), -- Grid position
	Vector3.new(4, 1, 4), -- Tile size
	Vector2.new(1, 1), -- Padding
	Vector2.new(10, 10) -- Grid size
)

-- Update tiles
RunService.Heartbeat:Connect(function(DeltaTime)
	for y = 1, #FloorTiles, 1 do
		for x = 1, #FloorTiles[y] do
			local part = FloorTiles[y][x]
			
			-- Sine wave example
			local old_x, old_z = part.Position.X, part.Position.Z
			local wave = math.sin((tick() * 2) + (y + x)) * 0.5
			
			-- for the wave, just add the y and x indexes together to get the unique index for each part.
			-- then add that to the tick. this makes it like a 'wave'.
			part.Position = Vector3.new(old_x, wave + 0.5, old_z)
		end
	end
end)


while true do
	local color = BrickColor.Random().Color
	
	for i = 1, 300 do
		PerlinNoiseTest(color, i / 300)
		ApplyColorMap()
		task.wait(0.03)
	end
	task.wait(1)
end

This was made using some code from the person in the video.

Also, a few colors might be a little distorted when applying noise. I believe this is because the colors are like (0.94, 0.32, 0.45) and the noise adds it so it goes over 1 on some values. It can probably be fixed by clamping the individual color values to 1 and 0.

To be clear, I am new to perlin noise, so I recommend reading this if you want more info:

Hope this helps with the colors!

2 Likes