ترقية
الدرس 11 من 18 في دورة لعبة Roblox: الدفاع عن الأبراج على Coddy.
يصبح البرج أقوى مع المستويات. المستوى سمة في نموذج البرج، Level، ويبدأ عند 1؛ يضيف كل مستوى مقدار ضرر البرج مرة أخرى، لذا يُلحق رامي السهام من المستوى 3 ضررًا مقداره 12.
تكلفة كل ترقية أعلى من سابقتها: جزء من سعر البرج، Settings.UpgradeCost، مضروبًا في المستوى الحالي. تُبقي math.floor الناتج عددًا صحيحًا:
local cost = math.floor(Settings.Towers[tower.Name].Price * Settings.UpgradeCost * level)على العميل، يؤدي النقر على برج إلى فتح Panel في HUD، حيث يظهر اسمه ومستواه وسعر الترقية التالية. يصيب النقر أحد أجزاء البرج، لذا تعثر target:FindFirstAncestorOfClass("Model") على البرج الذي ينتمي إليه. تعرض اللوحة المستوى الذي حدده الخادم: فهي تستمع إلى سمة Level في البرج وتُحدّث الرسم عند تغيّرها.
التحدي
متوسطفي DefenseServer:
- في
placeTower، عيّن السمةLevelللبرج إلى 1. - في
shoot، يكون الضررinfo.Damage * tower:GetAttribute("Level"). - اربط
remotes.Upgrade.OnServerEvent(player, tower): ارفض أي شيء ليس Instance ضمنtowers، واحسب التكلفة، وارفض العملية إن لم يتوفر المال، ثم اخصم المال وأضف 1 إلى المستوى.
في DefenseClient: اكتب showPanel() (العنوان Archer level 1، والزر Upgrade $45، واللوحة مرئية؛ ومخفية عند عدم اختيار أي شيء) وchoose(tower)؛ يؤدي النقر على برج إلى اختياره، ويُطلق زر Upgrade في اللوحة remotes.Upgrade مع البرج.
اضغط Play، ثم Check.
جرّب بنفسك
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Debris = game:GetService("Debris")
local Settings = require(game.ReplicatedStorage.Settings)
local remotes = game.ReplicatedStorage.Remotes
local enemies = workspace.Enemies
local towers = workspace.Towers
print("The base can take " .. Settings.BaseHealth .. " hits")
-- نقاط المسار بالترتيب (أسماؤها 1، 2، 3...)
local waypoints = workspace.Path.Waypoints:GetChildren()
table.sort(waypoints, function(a, b)
return tonumber(a.Name) < tonumber(b.Name)
end)
-- صحة القاعدة، بصفتها خاصية في workspace: يمكن لكل عميل قراءتها
workspace:SetAttribute("BaseHealth", Settings.BaseHealth)
-- يحصل كل لاعب على Money في لوحة الصدارة
Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local money = Instance.new("IntValue")
money.Name = "Money"
money.Value = Settings.StartMoney
money.Parent = leaderstats
end)
-- وصل عدو إلى القاعدة
local function damageBase(amount)
local health = math.max(0, workspace:GetAttribute("BaseHealth") - amount)
workspace:SetAttribute("BaseHealth", health)
end
-- حرّك عدوًا على طول المسار. يتوقف MoveTo عن المحاولة بعد 8 ثوانٍ ويُبلغ عن ذلك
-- (MoveToFinished بقيمة false)، لذا يُوجَّه العدو البطيء مجددًا حتى يصل.
local function walkPath(enemy)
local humanoid = enemy.Humanoid
for i = 2, #waypoints do
repeat
humanoid:MoveTo(waypoints[i].Position)
until humanoid.MoveToFinished:Wait() or not enemy.Parent
if not enemy.Parent then
return
end
end
-- وصل إلى القاعدة
damageBase(Settings.Enemies[enemy.Name].Damage)
enemy:Destroy()
end
-- عدو جديد عند البوابة، يسير على طول المسار
local function spawnEnemy(kind)
local enemy = ServerStorage.Enemies[kind]:Clone()
-- يُوضَع مباشرةً فوق أول نقطة في المسار
enemy:PivotTo(waypoints[1].CFrame + Vector3.new(0, 5, 0))
local info = Settings.Enemies[kind]
enemy.Humanoid.MaxHealth = info.Health
enemy.Humanoid.Health = info.Health
enemy.Humanoid.WalkSpeed = info.Speed
enemy.Parent = enemies
enemy.Humanoid.Died:Connect(function()
-- يحصل كل لاعب على المكافأة
for _, player in Players:GetPlayers() do
player.leaderstats.Money.Value += info.Reward
end
enemy:Destroy()
end)
task.spawn(walkPath, enemy)
return enemy
end
-- أقرب عدو حي ضمن نطاق نقطة معيّنة، أو nil
local function nearestEnemy(position, range)
local best, bestDistance = nil, range
for _, enemy in enemies:GetChildren() do
local root = enemy:FindFirstChild("HumanoidRootPart")
if root and enemy.Humanoid.Health > 0 then
local distance = (root.Position - position).Magnitude
if distance <= bestDistance then
best, bestDistance = enemy, distance
end
end
end
return best
end
-- ومضة ضوء من برج إلى هدفه
local function beam(from, to)
local ray = Instance.new("Part")
ray.Anchored = true
ray.CanCollide = false
ray.CanTouch = false
ray.Material = Enum.Material.Neon
ray.Color = Color3.fromRGB(255, 240, 150)
ray.Size = Vector3.new(0.2, 0.2, (to - from).Magnitude)
ray.CFrame = CFrame.lookAt((from + to) / 2, to)
ray.Parent = workspace
Debris:AddItem(ray, 0.1)
end
-- طلقة: ألحق الضرر بالهدف
local function shoot(tower, target, info)
local damage = info.Damage
local at = target.HumanoidRootPart.Position
target.Humanoid:TakeDamage(damage)
beam(tower.Head.Position, at)
end
-- دورة عمل البرج: صوّب نحو أقرب عدو ضمن المدى، وأطلق النار، ثم انتظر انتهاء فترة التهدئة
local function runTower(tower)
local info = Settings.Towers[tower.Name]
while tower.Parent do
local target = nearestEnemy(tower.Head.Position, info.Range)
if target then
tower.Head.CFrame = CFrame.lookAt(tower.Head.Position, target.HumanoidRootPart.Position)
shoot(tower, target, info)
task.wait(info.Cooldown)
else
task.wait(0.1)
end
end
end
-- ابنِ برجًا على منصة
local function placeTower(pad, kind)
local tower = ServerStorage.Towers[kind]:Clone()
tower:PivotTo(pad.CFrame + Vector3.new(0, pad.Size.Y / 2 + 1, 0))
tower.Parent = towers
pad:SetAttribute("Used", true)
task.spawn(runTower, tower)
end
-- يطلب العميل وضع برج على منصة. تحقّق من كل شيء: منصة موجودة فعلًا وغير مشغولة،
-- وبرج موجود فعلًا، وتوفّر المال اللازم لدفع ثمنه.
remotes.Place.OnServerEvent:Connect(function(player, pad, kind)
if typeof(pad) ~= "Instance" or pad.Parent ~= workspace.Pads or pad:GetAttribute("Used") then
return
end
local info = typeof(kind) == "string" and Settings.Towers[kind]
if not info then
return
end
local money = player.leaderstats.Money
if money.Value < info.Price then
return
end
money.Value -= info.Price
placeTower(pad, kind)
end)
-- موجة واحدة: أطلق أعداءها واحدًا تلو الآخر، ثم انتظر حتى يختفوا جميعًا
local function runWave(list)
for _, kind in list do
spawnEnemy(kind)
task.wait(Settings.SpawnGap)
end
while #enemies:GetChildren() > 0 do
task.wait(0.2)
end
end
-- الموجات، تبدأ كل واحدة منها بعد استراحة
for i, list in Settings.Waves do
task.wait(Settings.WaveBreak)
runWave(list)
end
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.