الإغماء
الدرس 12 من 20 في دورة لعبة Roblox: ساحات القتال على Coddy.
تُسبّب ضربة الاندفاع في الكومبو الذهول: يبقى هدفها متجمّدًا لمدة Settings.StunTime. لا يستطيع كائن Humanoid ذو قيمة WalkSpeed تساوي 0 المشي؛ لذا يحتفظ الذهول بالسرعة التي كانت لديه ويعيدها إليه.
تُشير السمة Stunned إلى الشخصية المصابة بالذهول. تقرؤها الروبوتات في الفصل 4 لتتوقف عن الهجوم، كما تمنع حدوث ذهول ثانٍ من حفظ القيمة 0 بوصفها السرعة التي ينبغي الرجوع إليها:
if character:GetAttribute("Stunned") then
return
endالتحدي
متوسطاكتب stun(humanoid) فوق swing: ارجع إذا كانت شخصيته تحمل بالفعل السمة Stunned؛ وإلا فأضِف هذه السمة، واحتفظ بقيمة WalkSpeed، واضبطها على 0، وبعد Settings.StunTime أعد السرعة وأزل السمة (إذا كانت الشخصية لا تزال موجودة). أوقِف هدف الضربة الثالثة من سلسلة الضربات.
اضغط على Play، ثم Check.
جرّب بنفسك
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)
local remotes = game.ReplicatedStorage.Remotes
local lastSwing = {} -- player -> وقت آخر ضربة سيف نفّذها
local combo = {} -- player -> { عدد الضربات المتتالية، وقت إصابة الضربة الأخيرة }
-- حركات السيف الخاصة بـ Roblox
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"
local lunge = Instance.new("Animation")
lunge.AnimationId = "rbxassetid://522638767"
print("Swords deal " .. Settings.SwordDamage .. " damage")
-- تمرّ كل ضربة في اللعبة من هنا
local function hurt(humanoid, amount)
if humanoid.Health <= 0 then
return
end
local character = humanoid.Parent
-- الصدّ يمتصّ معظم ضرر الضربة
if character:GetAttribute("Blocking") then
amount *= Settings.BlockMultiplier
end
humanoid:TakeDamage(amount)
end
-- ضربة بالسيف: تُشغَّل الحركة، ثم يُصاب كل من داخل الصندوق أمامك
local function swing(player)
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root or character.Humanoid.Health <= 0 then
return
end
local now = time()
if lastSwing[player] and now - lastSwing[player] < Settings.SwingCooldown then
return
end
lastSwing[player] = now
-- ثلاث ضربات متتالية تشكّل سلسلة ضربات؛ الثالثة منها اندفاع
local c = combo[player]
if c and now - c.last <= Settings.ComboWindow then
c.count = c.count % 3 + 1
else
c = { count = 1 }
combo[player] = c
end
c.last = now
local finisher = c.count == 3
character.Humanoid.Animator:LoadAnimation(finisher and lunge or slash):Play()
-- الصندوق أمامك، ولا يشمل جسمك أبدًا
local params = OverlapParams.new()
params.FilterDescendantsInstances = { character }
local box = root.CFrame * CFrame.new(0, 0, -3)
local hit = {} -- كل humanoid مرة واحدة في كل ضربة
for _, part in workspace:GetPartBoundsInBox(box, Settings.HitboxSize, params) do
local humanoid = part.Parent:FindFirstChildOfClass("Humanoid")
if humanoid and not hit[humanoid] then
hit[humanoid] = true
hurt(humanoid, Settings.ComboDamage[c.count])
end
end
end
-- القدرات حسب الاسم: ما تفعله كل واحدة
local abilities = {}
function abilities.Dash(player, character, root)
root.AssemblyLinearVelocity = root.CFrame.LookVector * Settings.DashSpeed + Vector3.new(0, 15, 0)
end
-- يُصاب كل من حولك ويُدفَع بعيدًا عنك
function abilities.Slam(player, character, root)
local params = OverlapParams.new()
params.FilterDescendantsInstances = { character }
local hit = {}
for _, part in workspace:GetPartBoundsInRadius(root.Position, Settings.SlamRadius, params) do
local humanoid = part.Parent:FindFirstChildOfClass("Humanoid")
local theirRoot = part.Parent:FindFirstChild("HumanoidRootPart")
if humanoid and theirRoot and not hit[humanoid] then
hit[humanoid] = true
hurt(humanoid, Settings.SlamDamage)
local away = (theirRoot.Position - root.Position) * Vector3.new(1, 0, 1)
if away.Magnitude > 0 then
away = away.Unit
end
theirRoot:ApplyImpulse((away * Settings.SlamKnockback + Vector3.new(0, 40, 0)) * theirRoot.AssemblyMass)
end
end
end
function abilities.Block(player, character)
character:SetAttribute("Blocking", true)
task.delay(Settings.BlockTime, function()
if character.Parent then
character:SetAttribute("Blocking", nil)
end
end)
end
-- يطلب العميل قدرةً باسمها. يتحقّق الخادم منها: أن تكون قدرةً حقيقية
-- قدرة صالحة، ولاعبًا حيًا، وانتهاء فترة الانتظار الخاصة بها. وموعد جاهزيتها مجددًا
-- يُخزَّن كسمة للاعب، حتى تتمكن شاشته من إظهاره.
remotes.Ability.OnServerEvent:Connect(function(player, name)
if typeof(name) ~= "string" or not abilities[name] then
return
end
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root or character.Humanoid.Health <= 0 then
return
end
local now = workspace:GetServerTimeNow()
if now < (player:GetAttribute(name .. "ReadyAt") or 0) then
return
end
player:SetAttribute(name .. "ReadyAt", now + Settings.Cooldowns[name])
abilities[name](player, character, root)
end)
-- يحصل كل لاعب على Kills في لوحة المتصدرين، وعلى سيف مع كل حياة جديدة
Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local kills = Instance.new("IntValue")
kills.Name = "Kills"
kills.Parent = leaderstats
player.CharacterAdded:Connect(function()
local sword = ServerStorage.Sword:Clone()
sword.Parent = player.Backpack
sword.Activated:Connect(function()
swing(player)
end)
end)
end)
-- دمية التدريب: يتغير شريط صحتها مع صحتها، والدمية التي تُهزم
-- تعود بعد قليل، بنسخة جديدة في المكان نفسه
local function setupDummy(dummy)
local humanoid = dummy.Humanoid
humanoid.HealthChanged:Connect(function(health)
dummy.HealthBar.Back.Fill.Size = UDim2.fromScale(health / humanoid.MaxHealth, 1)
end)
humanoid.Died:Connect(function()
local spot = dummy:GetPivot()
task.wait(0.5)
dummy:Destroy()
task.wait(Settings.DummyRespawn)
local fresh = ServerStorage.Dummy:Clone()
fresh:PivotTo(spot)
fresh.Parent = workspace
setupDummy(fresh)
end)
end
setupDummy(workspace.Dummy)
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.