Menu
CoddyTech

Beim Beitreten laden

Lektion 21 von 21 im Kurs Roblox-Spiel: Endloser Turm von Coddy.

Die Speicherungen sind vorhanden; jetzt lies sie wieder aus. GetAsync gibt zurück, was unter einem Schlüssel gespeichert wurde, oder nil für einen Spieler, der noch nie gespielt hat. Der Aufruf kann auch fehlschlagen, deshalb kommt er in ein pcall, das zurückgibt, ob es funktioniert hat, und anschließend den Wert:

local ok, saved = pcall(function()
	return coinStore:GetAsync(player.UserId)
end)
if ok and saved then
	coins.Value = saved.Coins or 0
end

or 0 deckt eine Speicherung aus einer älteren Spielversion ab, in der es kein solches Feld gab.

challenge icon

Aufgabe

Schwer

Gib den Spielern zurück, was sie zuletzt gespeichert haben.

  1. Füge in PlayerAdded nach dem Erstellen von BestTime Folgendes ein: local ok, saved = pcall(function() return towerStore:GetAsync(player.UserId) end).
  2. Wenn ok and saved gilt, setze Wins auf saved.Wins or 0 und BestTime auf saved.BestTime or 0.

Drücke auf „Spielen“, gewinne, drücke auf Stop und dann erneut auf „Spielen“: Deine Wins und BestTime sind wieder da. Drücke dann auf „Prüfen“.

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 DataStoreService = game:GetService("DataStoreService")
local Settings = require(game.ReplicatedStorage.Settings)

local stages = ServerStorage.Stages
local lobbySpawn = workspace.Lobby.SpawnLocation
local towerStore = DataStoreService:GetDataStore("Tower")
local tower = nil
local towerStages = {}
local lava = nil
local roundStart = 0
local finished = {}

print("Each tower has " .. Settings.StageCount .. " stages")

-- Jeder Spieler erhält Wins, Stage und BestTime 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

	local best = Instance.new("NumberValue")
	best.Name = "BestTime"
	best.Parent = leaderstats

	-- Lektion 21: Hier kommt Load on Join hin
	-- Ein Spieler, der herunterfällt, startet erneut auf der zuletzt erreichten Stage,
	-- es sei denn, die Lava hat sie bereits 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 nach dem Betreten 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 dauerhaft zu seinem Slide-Versatz und zurück
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 in 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 jedes Hindernis einer Stage anhand seiner 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 Stage 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 sind die Abschnitte schwieriger: 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 oben auf dem Turm; gibt die Kopie und die neue Oberkante 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 Spitze des Turms: 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
	local seconds = math.floor((time() - roundStart) * 10) / 10
	local best = player.leaderstats.BestTime
	if best.Value == 0 or seconds < best.Value then
		best.Value = seconds
	end
	print(player.Name .. " reached the top in " .. seconds .. " seconds")
	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 Spitze des Turms
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)
	roundStart = time()
	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

-- Speichern: Wins und BestTime
local function saveProgress(player)
	local data = {
		Wins = player.leaderstats.Wins.Value,
		BestTime = player.leaderstats.BestTime.Value,
	}
	pcall(function()
		towerStore:SetAsync(player.UserId, data)
	end)
end

Players.PlayerRemoving:Connect(saveProgress)

game:BindToClose(function()
	for _, player in Players:GetPlayers() do
		saveProgress(player)
	end
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
quiz iconTeste dich selbst

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

Übe selbstständig: Roblox-Playground