Menu
CoddyTech

הזמנים הטובים ביותר ושמירות

שיעור 18 מתוך 18 בקורס משחק Roblox: מגדל אינסופי של Coddy.

שחקני מהירות מאריכים את משך החיים של משחקי מכשולים. מדוד את הזמן של כל טיפוס, שמור את הזמן הטוב ביותר של כל שחקן בטבלת הדירוג, ושמור אותו יחד עם הניצחונות שלו, כדי שיופיע גם בפעם הבאה.

time() הוא מספר השניות שהמשחק פועל. תעד את הזמן כשהסיבוב מתחיל; בפסגה, ההפרש הוא זמן הטיפוס. עגל לעשיריות בשביל הלוח:

local seconds = math.floor((time() - roundStart) * 10) / 10

הזמן הטוב ביותר הוא הקטן ביותר, ו-0 פירושו שעדיין אין זמן. השמירה משתמשת ב-DataStore, כמו במשחק אמיתי: GetAsync כששחקן מצטרף, SetAsync כשהוא עוזב וכשהשרת נסגר (game:BindToClose). שתי הפעולות עלולות להיכשל מצד Roblox, לכן יש לעטוף אותן ב-pcall.

challenge icon

אתגר

קשה
  1. בחלק העליון, קבלו את DataStoreService, מאגר נתונים בשם Tower, ואת local roundStart = 0. בתוך startRound, הגדירו roundStart = time().
  2. תנו לשחקנים ערך NumberValue בשם BestTime בתוך leaderstats, וטענו את Wins ואת BestTime השמורים שלהם כשהם מצטרפים.
  3. בתוך reachTop, חשבו את זמן הטיפוס בשניות; אם BestTime הוא 0 או שהטיפוס מהיר יותר, הגדירו אותו. הדפיסו Name reached the top in 12.3 seconds במקום השורה הישנה.
  4. כתבו את saveProgress(player) (שמרו טבלה של Wins ושל BestTime תחת UserId של השחקן) וקראו לה בעת PlayerRemoving ועבור כל שחקן בתוך game:BindToClose.

לחצו על Play, נצחו, לחצו על Stop ואז שוב על Play: השיא שלכם עדיין שם. לאחר מכן לחצו על Check.

נסו בעצמכם

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")

-- כל שחקן מקבל Wins ו-Stage בטבלת המובילים
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

	-- שחקן שנופל מתחיל שוב בשלב האחרון שאליו הגיע,
	-- אלא אם הלבה כבר כיסתה אותו: במקרה כזה הוא ממתין בלובי
	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
	print(player.Name .. " reached the top")
	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)
	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

-- לולאת הסיבובים
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 iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה משחק Roblox: מגדל אינסופי