Thời gian tốt nhất
Bài học 19 trên 21 trong khóa học Trò chơi Roblox: Tháp bất tận của Coddy.
Người chơi speedrun kéo dài thử thách obby. Hãy tính thời gian mỗi lần leo và lưu thành tích tốt nhất của từng người chơi trên bảng xếp hạng.
time() là số giây trò chơi đã chạy. Ghi lại thời điểm vòng chơi bắt đầu; khi lên đến đỉnh, lấy hiệu hai thời điểm để tính thời gian leo. Làm tròn đến một chữ số thập phân để hiển thị trên bảng:
local lap = math.floor((time() - lapStart) * 10) / 10 -- 7.46 giây thành 7.4 giâyThời gian tốt nhất là thời gian ngắn nhất, còn 0 nghĩa là chưa có thành tích nào. NumberValue lưu giá trị này vì IntValue chỉ lưu được số nguyên.
Thử thách
KhóGhi thời gian mỗi lần leo và lưu thành tích tốt nhất của từng người chơi.
- Thêm một NumberValue
BestTimevào leaderstats;startRoundđặtroundStart = time()ở cấp cao nhất. - Trong
reachTop:local seconds = math.floor((time() - roundStart) * 10) / 10; nếu BestTime bằng 0 hoặc lớn hơn, hãy đặt giá trị đó thànhseconds. - Thay vào đó, in ra
player.Name .. " reached the top in " .. seconds .. " seconds".
Nhấn Chơi và giành chiến thắng: thời gian của bạn sẽ hiển thị trên bảng xếp hạng. Sau đó, nhấn Kiểm tra.
Tự làm thử
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")
-- Mỗi người chơi có Wins và Stage trên bảng xếp hạng
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
local stage = Instance.new("IntValue")
stage.Name = "Stage"
stage.Parent = leaderstats
-- Người chơi bị rơi sẽ bắt đầu lại ở màn cuối cùng họ đã đến,
-- trừ khi dung nham đã phủ kín màn đó: khi ấy họ chờ ở sảnh
player.CharacterAdded:Connect(function(character)
task.wait()
local checkpoint = towerStages[stage.Value]
local covered = checkpoint and lava and checkpoint.Start.Position.Y < lava.Position.Y + lava.Size.Y / 2
if checkpoint and not covered and not finished[player] then
character:PivotTo(checkpoint.Start.CFrame + Vector3.new(0, 4, 0))
end
end)
end)
-- Bảng thông báo trong sảnh
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
-- Chạm vào bất cứ thứ gì mang nhãn Kill sẽ mất một mạng
local function killOnTouch(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health = 0
end
end
-- Bậc biến mất mờ dần ngay sau khi có người đáp xuống, rồi hiện lại
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
-- Tia laser trượt đến vị trí lệch theo Slide rồi quay lại, lặp mãi
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
-- Tấm bật đẩy người đáp xuống lên không trung
local function bounce(hit)
local root = hit.Parent:FindFirstChild("HumanoidRootPart")
if root then
root.AssemblyLinearVelocity = Vector3.new(0, Settings.BouncePower, 0)
end
end
-- Các vật xoay nhích một chút sau mỗi khung hình
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)
-- Kích hoạt mọi chướng ngại vật trong một màn dựa trên nhãn của chúng
local function setupStage(stage, index)
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
-- Chạm đến Start của một màn sẽ cập nhật bảng xếp hạng
stage.Start.Touched:Connect(function(hit)
local player = Players:GetPlayerFromCharacter(hit.Parent)
if player and player.leaderstats.Stage.Value < index then
player.leaderstats.Stage.Value = index
end
end)
end
-- Các màn càng lên cao càng khó: một phần ba phía dưới dễ, một phần ba phía trên khó
local function pickStage(index)
local difficulty = math.ceil(index / Settings.StageCount * 3)
local choices = {}
for _, stage in stages:GetChildren() do
if stage:GetAttribute("Difficulty") == difficulty then
table.insert(choices, stage)
end
end
return choices[math.random(1, #choices)]
end
-- Đặt bản sao của mô hình lên đỉnh tháp; trả về bản sao và độ cao mới của đỉnh tháp
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
-- Đỉnh tháp: ghi nhận một lần thắng rồi trở về sảnh
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
-- Bài học 19: thêm Best Times vào đây
print(player.Name .. " reached the top")
hit.Parent:PivotTo(lobbySpawn.CFrame + Vector3.new(0, 4, 0))
end
-- Tạo tháp mới ngẫu nhiên từ dưới lên
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(i), top)
top = newTop
setupStage(stage, i)
towerStages[i] = stage
end
local finish = stack(ServerStorage.Finish, top)
finish.FinishPad.Touched:Connect(reachTop)
return top
end
-- Dung nham dâng từ mặt đất lên sát dưới đỉnh tháp
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 = {}
for _, player in Players:GetPlayers() do
player.leaderstats.Stage.Value = 0
end
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
local function endRound()
for _, player in Players:GetPlayers() do
if player.Character and not finished[player] then
player.Character:PivotTo(lobbySpawn.CFrame + Vector3.new(0, 4, 0))
end
player.leaderstats.Stage.Value = 0
end
tower:Destroy()
lava:Destroy()
towerStages = {}
end
-- Vòng lặp của mỗi lượt chơi
while true do
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
endRound()
end
Tất cả bài học trong Trò chơi Roblox: Tháp bất tận
4Biến nó thành trò chơi
Màn chơi trên bảng xếp hạngTự luyện tập: Playground Roblox