Bestzeiten und Spielstände
Lektion 18 von 18 im Kurs Roblox-Spiel: Endloser Turm von Coddy.
Speedrunner lassen Obbys dauerhaft interessant bleiben. Miss jede Kletterpartie, zeige für jeden Spieler seine Bestzeit in der Bestenliste an und speichere sie zusammen mit seinen Wins, damit sie beim nächsten Mal noch vorhanden ist.
time() gibt die Anzahl der Sekunden an, die das Spiel bereits läuft. Merke dir den Wert, wenn die Runde beginnt; oben angekommen ist die Differenz die Kletterzeit. Runde sie für die Bestenliste auf Zehntelsekunden:
local seconds = math.floor((time() - roundStart) * 10) / 10Die Bestzeit ist die kürzeste Zeit, und 0 bedeutet, dass es noch keine gibt. Zum Speichern wird ein DataStore verwendet, wie in einem echten Spiel: GetAsync, wenn ein Spieler beitritt, SetAsync, wenn er das Spiel verlässt und wenn der Server geschlossen wird (game:BindToClose). Beides kann aufseiten von Roblox fehlschlagen, also verpacke die Aufrufe in pcall.
Aufgabe
Schwer- Hole dir weiter oben
DataStoreService, einen DataStore namensTowerundlocal roundStart = 0. Setze instartRoundroundStart = time(). - Gib den Spielern in leaderstats einen NumberValue namens
BestTimeund lade beim Beitritt ihre gespeicherten Werte fürWinsundBestTime. - Berechne in
reachTopdie Sekunden für den Aufstieg; wenn BestTime 0 ist oder der Aufstieg schneller war, setze den Wert. GibName reached the top in 12.3 secondsstatt der alten Zeile aus. - Schreibe
saveProgress(player)(speichere eine Tabelle mit Wins und BestTime unter der UserId des Spielers) und rufe die Funktion beiPlayerRemovingsowie für jeden Spieler ingame:BindToCloseauf.
Drücke Play, gewinne, drücke Stop und dann erneut Play: Deine Bestzeit ist noch da. Dann Check.
Probier es selbst
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")
-- Jeder Spieler erhält Wins und Stage auf der Bestenliste
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
-- Ein Spieler, der herunterfällt, beginnt wieder auf der letzten erreichten Stufe,
-- es sei denn, die Lava hat sie bedeckt: Dann wartet er in der Lobby
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)
-- Die Anzeigetafel in der 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
-- Alles mit dem Tag Kill beendet ein Leben
local function killOnTouch(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health = 0
end
end
-- Eine verschwindende Stufe wird kurz nachdem jemand darauf landet durchsichtig und erscheint dann wieder
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
-- Ein Laser gleitet zu seinem Slide-Versatz und zurück, immer wieder
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
-- Ein Sprungfeld schleudert jeden, der darauf landet, in die Luft
local function bounce(hit)
local root = hit.Parent:FindFirstChild("HumanoidRootPart")
if root then
root.AssemblyLinearVelocity = Vector3.new(0, Settings.BouncePower, 0)
end
end
-- Spinner drehen sich bei jedem Frame ein Stück
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)
-- Aktiviere alle Hindernisse einer Stufe anhand ihrer Tags
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
-- Das Erreichen von Start einer Stufe wird auf der Bestenliste gezählt
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
-- Weiter oben liegen schwierigere Stufen: das untere Drittel ist leicht, das obere schwer
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
-- Platziere eine Kopie eines Modells auf dem Turm; gibt die Kopie und die neue Höhe der Turmspitze zurück
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
-- Die Turmspitze: ein Sieg und zurück zur 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
-- Baue einen neuen zufälligen Turm von unten nach oben
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
-- Die Lava steigt vom Boden bis knapp unter die Turmspitze
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
-- Die Rundenschleife
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
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Roblox-Spiel: Endloser Turm
4Mach ein Spiel daraus
Bühne auf der Bestenliste