Round After Round
Lesson 14 of 18 in Coddy's Roblox Game: Endless Tower course.
One round is a demo; a game goes round after round. Put the lobby countdown, the round and its countdown inside while true do, and add an endRound() that tidies up when the time runs out:
- players still on the tower go back to the lobby,
- the tower and the lava are destroyed, so the next round builds a fresh tower in their place.
Destroy removes an instance and everything inside it, so destroying the tower Model removes every stage at once. The loop never ends, so it goes at the very bottom of the script: nothing after it would ever run.
Challenge
Medium- Write
endRound(): move every player who has not finished to 4 studs abovelobbySpawn, destroytowerandlava, and emptytowerStages. - At the bottom, wrap the lobby countdown,
startRound()and the round countdown inwhile true do, and callendRound()at the end of each turn.
This lesson's rounds are short. Press Play. Then Check.
Try it yourself
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local Settings = require(game.ReplicatedStorage.Settings)
local stages = ServerStorage.Stages
local lobbySpawn = workspace.Lobby.SpawnLocation
local tower = nil
local towerStages = {}
local lava = nil
local finished = {}
print("Each tower has " .. Settings.StageCount .. " stages")
-- Every player gets Wins on the leaderboard
Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local wins = Instance.new("IntValue")
wins.Name = "Wins"
wins.Parent = leaderstats
end)
-- The board in the lobby
local gui = Instance.new("SurfaceGui")
gui.Parent = workspace.Lobby.Board
local boardLabel = Instance.new("TextLabel")
boardLabel.Name = "Status"
boardLabel.Size = UDim2.fromScale(1, 1)
boardLabel.BackgroundColor3 = Color3.fromRGB(25, 25, 35)
boardLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
boardLabel.TextScaled = true
boardLabel.Text = "Endless Tower"
boardLabel.Parent = gui
local function setBoard(text)
boardLabel.Text = text
end
-- Anything tagged Kill ends a life
local function killOnTouch(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health = 0
end
end
-- A vanishing step fades soon after someone lands on it, then comes back
local function makeVanish(part)
part.Touched:Connect(function(hit)
if part:GetAttribute("Gone") or not hit.Parent:FindFirstChild("Humanoid") then
return
end
part:SetAttribute("Gone", true)
task.wait(Settings.VanishDelay)
part.Transparency = 0.8
part.CanCollide = false
task.wait(Settings.VanishTime)
part.Transparency = 0
part.CanCollide = true
part:SetAttribute("Gone", nil)
end)
end
-- A laser slides to its Slide offset and back, forever
local function makeSlide(part)
local info = TweenInfo.new(Settings.SlideTime, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, -1, true)
local goal = { Position = part.Position + part:GetAttribute("Slide") }
TweenService:Create(part, info, goal):Play()
end
-- A bounce pad throws whoever lands on it up into the air
local function bounce(hit)
local root = hit.Parent:FindFirstChild("HumanoidRootPart")
if root then
root.AssemblyLinearVelocity = Vector3.new(0, Settings.BouncePower, 0)
end
end
-- Spinners turn a little every frame
RunService.Heartbeat:Connect(function(dt)
for _, spinner in CollectionService:GetTagged("Spinner") do
if spinner:IsDescendantOf(workspace) then
spinner:PivotTo(spinner:GetPivot() * CFrame.Angles(0, math.rad(Settings.SpinSpeed) * dt, 0))
end
end
end)
-- Turn on every obstacle in a stage, by its tags
local function setupStage(stage)
for _, part in stage:GetDescendants() do
if part:HasTag("Kill") then
part.Touched:Connect(killOnTouch)
end
if part:HasTag("Vanish") then
makeVanish(part)
end
if part:HasTag("Conveyor") then
part.AssemblyLinearVelocity = part.CFrame.LookVector * Settings.BeltSpeed
end
if part:HasTag("Slider") then
makeSlide(part)
end
if part:HasTag("Bounce") then
part.Touched:Connect(bounce)
end
end
end
-- Any stage, at random
local function pickStage()
local all = stages:GetChildren()
return all[math.random(1, #all)]
end
-- Put a copy of a model on top of the tower; returns the copy and the new top
local function stack(template, bottom)
local copy = template:Clone()
local box, size = copy:GetBoundingBox()
local lift = bottom - (box.Position.Y - size.Y / 2)
copy:PivotTo(copy:GetPivot() + Vector3.new(0, lift, 0))
copy.Parent = tower
return copy, bottom + size.Y
end
-- The top of the tower: a win, and back to the lobby
local function reachTop(hit)
local player = Players:GetPlayerFromCharacter(hit.Parent)
if not player or finished[player] then
return
end
finished[player] = true
player.leaderstats.Wins.Value += 1
print(player.Name .. " reached the top")
hit.Parent:PivotTo(lobbySpawn.CFrame + Vector3.new(0, 4, 0))
end
-- Build a new random tower, bottom up
local function buildTower()
tower = Instance.new("Model")
tower.Name = "Tower"
tower.Parent = workspace
towerStages = {}
local top = 0
for i = 1, Settings.StageCount do
local stage, newTop = stack(pickStage(), top)
top = newTop
setupStage(stage)
towerStages[i] = stage
end
local finish = stack(ServerStorage.Finish, top)
finish.FinishPad.Touched:Connect(reachTop)
return top
end
-- Lava rises from the ground to just under the top of the tower
local function startLava(top)
lava = Instance.new("Part")
lava.Name = "Lava"
lava.Anchored = true
lava.CanCollide = false
lava.Size = Vector3.new(30, 2, 30)
lava.Position = Vector3.new(0, -2, 0)
lava.Color = Color3.fromRGB(255, 90, 20)
lava.Material = Enum.Material.Neon
lava.Parent = workspace
lava.Touched:Connect(killOnTouch)
local info = TweenInfo.new(top / Settings.LavaSpeed, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false, Settings.LavaDelay)
TweenService:Create(lava, info, { Position = Vector3.new(0, top - 2, 0) }):Play()
end
local function startRound()
finished = {}
local top = buildTower()
startLava(top)
for _, player in Players:GetPlayers() do
if player.Character then
player.Character:PivotTo(towerStages[1].Start.CFrame + Vector3.new(0, 4, 0))
end
end
end
-- One round
for i = Settings.Intermission, 1, -1 do
setBoard("Next tower in " .. i)
task.wait(1)
end
startRound()
for i = Settings.RoundLength, 1, -1 do
setBoard("Climb! " .. i .. " seconds left")
task.wait(1)
end
This lesson includes a short quiz. Start the lesson to answer it and track your progress.