This looks like something fun to make!
I am neglecting some features for instance it has a sine wave like effect
For the sine wave, I threw something together to attempt to mimic it, and I think this might help with that part you are missing.
local RunService = game:GetService("RunService")
local DanceFloor = game:GetService("Workspace"):WaitForChild("DanceFloor") -- Folder in workspace.
local FloorTiles = {} -- 2D array containing each tile
-- 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 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] = {}
-- 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
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
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
)
-- Sine wave example
RunService.Heartbeat:Connect(function(DeltaTime)
for y = 1, #FloorTiles, 1 do
for x = 1, #FloorTiles[y] do
local part = FloorTiles[y][x]
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)
I’ll drop a quick explanation here,
I store all the parts in a 2D array, which is like a grid that tells me where each tile is, and importantly, I can index them using X and Y coordinates.
Then, I loop through each part from top left, to bottom right. For every part, I add a sine wave to its Y position, which makes the wave effect. (I am not very knowledgeable about trigonometry or those functions in general, so if I say something wrong, please correct me.). But, I also have to add something to the sine wave in order to make each part offset from the wave. So, I add the X and Y values of each part together to get the part number of the part. (This is sort of hard for me to articulate, as I am not very good at explaining some things, so I’ll just say that the part number is like the number of the part, ex: part 1, part 2, part 3, etc.) Then, I add this value to the sine wave to offset the part from the wave. which makes it further along the wave than the parts before it. (Again, I apologize if this is unclear, I am not the best explainer.)
[EDIT] Whoops, I realized that the dance floor that I made was slower than the video you provided, So, just change the *2 on line 70 to make it faster or slower. Larger numbers are faster.
local wave = math.sin((tick() * 2) + (y + x)) * 0.5 -- Change the tick() * 2 to whatever you want.
I’m not saying this is how Mad City does it, but it could be a possibility.
Video of it in action:
Hope this helps with that aspect of it!
Good luck with your project!