Menu
CoddyTech
flag Ar iconالعربيةdown icon

أفضل الأوقات وعمليات الحفظ

الدرس 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، وDataStore باسم 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.

اضغط تشغيل، واربح، ثم اضغط «إيقاف»، وشغّل اللعبة مجددًا: سيظل أفضل وقت لك محفوظًا. ثم اضغط تحقّق.

جرّب بنفسك

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: البرج اللانهائي