שמירה ביציאה
שיעור 20 מתוך 21 בקורס משחק Roblox: מגדל אינסופי של Coddy.
הניצחונות והזמנים הטובים ביותר עדיין צריכים להישאר לפעם הבאה. Roblox שומר נתונים בין ביקורים בתוך DataStore, טבלה בשרתים של Roblox שנשארת גם אחרי שהמשחק נסגר. שמרו כשהשחקן עוזב, ולכל מי שעדיין משחק כשהשרת נסגר:
local coinStore = DataStoreService:GetDataStore("Coins")
local function save(player)
pcall(function()
coinStore:SetAsync(player.UserId, { Coins = player.leaderstats.Coins.Value })
end)
end
Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
for _, player in Players:GetPlayers() do
save(player)
end
end)שמירה עלולה להיכשל בצד של Roblox, וכישלון יעצור את הסקריפט, לכן היא מתבצעת בתוך pcall. המפתח הוא UserId של השחקן, שלא משתנה לעולם, בניגוד לשם שלו.
אתגר
קשהשמור את Wins ואת BestTime של כל שחקן כשהוא עוזב.
- קרוב לתחילת הקוד:
local DataStoreService = game:GetService("DataStoreService")וגםlocal towerStore = DataStoreService:GetDataStore("Tower"). - כתוב את
saveProgress(player): בתוךpcall, השתמש ב-towerStore:SetAsync(player.UserId, { Wins = ..., BestTime = ... })כדי לשמור את הנתונים מתוך ה-leaderstats שלו. - קרא לפונקציה בעת
Players.PlayerRemoving, ולכל שחקן בתוךgame:BindToClose.
לחץ על „שחק”, נצח ולחץ על עצור: ה-Wins שלך יישמרו כדי שהשיעור הבא יוכל לטעון אותם. ואז לחץ על „בדיקה”.
נסו בעצמכם
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 roundStart = 0
local finished = {}
print("Each tower has " .. Settings.StageCount .. " stages")
-- כל שחקן מקבל Wins, Stage ו-BestTime בלוח המובילים
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
-- שחקן שנופל מתחיל שוב בשלב האחרון שאליו הגיע,
-- אלא אם הלבה כיסתה אותו: במקרה כזה הוא ממתין בלובי
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)
-- הלוח בלובי
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
-- כל דבר שמסומן בתג Kill מסיים את חייו של השחקן
local function killOnTouch(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health = 0
end
end
-- מדרגה נעלמת דוהה זמן קצר אחרי שמישהו נוחת עליה, ואז חוזרת
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
-- לייזר מחליק למיקום המוזז לפי Slide ובחזרה, ללא הפסקה
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
-- משטח קפיצה מעיף לאוויר את מי שנוחת עליו
local function bounce(hit)
local root = hit.Parent:FindFirstChild("HumanoidRootPart")
if root then
root.AssemblyLinearVelocity = Vector3.new(0, Settings.BouncePower, 0)
end
end
-- העצמים המסתובבים מסתובבים מעט בכל פריים
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)
-- הפעל את כל המכשולים בשלב לפי התגים שלהם
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
-- הגעה ל-Start של שלב נרשמת בלוח המובילים
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
-- השלבים נעשים קשים יותר ככל שעולים: השליש התחתון קל, השליש העליון קשה
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
-- מקם עותק של מודל על גבי המגדל; מחזיר את העותק ואת הגובה החדש של המגדל
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
-- ראש המגדל: ניצחון וחזרה ללובי
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
-- בנה מגדל אקראי חדש מלמטה למעלה
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
-- הלבה עולה מהקרקע עד מעט מתחת לראש המגדל
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
-- שיעור 20: שמירה בעת יציאה תתווסף כאן
-- לולאת הסיבובים
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
כל השיעורים ביחידה משחק Roblox: מגדל אינסופי
תרגלו בעצמכם: Roblox אונליין