Charger à la connexion
Leçon 21 sur 21 du cours Jeu Roblox : Tour infinie de Coddy.
Les sauvegardes sont là ; il faut maintenant les relire. GetAsync renvoie la valeur enregistrée sous une clé, ou nil pour un joueur qui n’a jamais joué. Cette opération peut aussi échouer, donc elle est placée dans un pcall, qui renvoie si elle a réussi, puis la valeur :
local ok, saved = pcall(function()
return coinStore:GetAsync(player.UserId)
end)
if ok and saved then
coins.Value = saved.Coins or 0
endor 0 couvre le cas d’une sauvegarde provenant d’une ancienne version du jeu qui ne possédait pas ce champ.
Défi
DifficileRedonne aux joueurs ce qu’ils avaient enregistré la dernière fois.
- Dans
PlayerAdded, après avoir créé BestTime :local ok, saved = pcall(function() return towerStore:GetAsync(player.UserId) end). - Si
ok and saved, définis Wins sursaved.Wins or 0et BestTime sursaved.BestTime or 0.
Clique sur « Jouer », gagne, clique sur Stop puis sur « Jouer » à nouveau : tes Wins et BestTime sont de retour. Ensuite, clique sur « Vérifier ».
Essayez vous-même
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")
-- Chaque joueur a Wins, Stage et BestTime dans le classement
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
-- Leçon 21 : le chargement à la connexion se fait ici
-- un joueur qui tombe repart de la dernière étape atteinte,
-- sauf si la lave l’a recouverte : il attend alors dans le hall
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)
-- Le panneau dans le hall
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
-- Tout objet portant le tag Kill met fin à une vie
local function killOnTouch(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health = 0
end
end
-- Une plateforme évanescente disparaît peu après qu’un joueur y atterrit, puis réapparaît
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
-- Un laser glisse jusqu’au décalage Slide, puis revient, indéfiniment
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
-- Un tremplin propulse dans les airs quiconque atterrit dessus
local function bounce(hit)
local root = hit.Parent:FindFirstChild("HumanoidRootPart")
if root then
root.AssemblyLinearVelocity = Vector3.new(0, Settings.BouncePower, 0)
end
end
-- Les Spinners tournent un peu à chaque image
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)
-- Active tous les obstacles d’une étape selon leurs 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
-- atteindre le Start d’une étape est pris en compte dans le classement
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
-- Les étapes sont plus difficiles en hauteur : le tiers inférieur est facile, le tiers supérieur est difficile
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
-- Place une copie d’un modèle au sommet de la tour ; renvoie la copie et la nouvelle hauteur du sommet
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
-- Le sommet de la tour : une victoire, puis retour au 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
-- Construit une nouvelle tour aléatoire, de bas en haut
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
-- La lave monte depuis le sol jusqu’à juste en dessous du sommet de la tour
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
-- Sauvegarde : Wins et 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)
-- La boucle des manches
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
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Jeu Roblox : Tour infinie
4Transformez-le en jeu
Placez un score au classementEntraînez-vous par vous-même : Playground Roblox