Menu
CoddyTech

اندفع عند Q

الدرس 7 من 25 في دورة لعبة Roblox: ساحة القتال على Coddy.

الاندفاع دفعة: إن ضبط AssemblyLinearVelocity للجذر يقذف الشخصية. لكن Roblox يتيح لجهاز كل لاعب تشغيل فيزياء شخصيته، لذا فإن الدفعة التي يضبطها الخادم لا تحركه إلا قليلًا. الخادم هو من يقرر، بينما تنفذ LocalScript الخاصة باللاعب الدفعة.

يحتفظ الخادم بقدراته في جدول، حسب الاسم، وعند الموافقة على الاندفاع تُرسل الموافقة إلى عميل ذلك اللاعب باستخدام FireClient، حيث يستقبلها OnClientEvent:

remotes.Ability.OnClientEvent:Connect(function(name)
	if name == "Hop" then
		root.AssemblyLinearVelocity = Vector3.new(0, 50, 0)
	end
end)
challenge icon

التحدي

متوسط

اجعل الاندفاع على Q: يوافق الخادم، فيدفع جهازك شخصيتك.

  1. في BattleServer، استبدل الطباعة بجدول abilities: يستدعي abilities.Dash(player) الدالة remotes.Ability:FireClient(player, "Dash").
  2. يستدعي المعالج abilities[name](player, character, root) عند وجودها.
  3. في BattleClient، عند remotes.Ability.OnClientEvent مع "Dash"، اضبط سرعة الجذر على root.CFrame.LookVector * Settings.DashSpeed + Vector3.new(0, 15, 0).

اضغط «العب» ثم اضغط Q: ستندفع إلى الأمام. ثم اضغط «تحقق».

جرّب بنفسك

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)

local remotes = game.ReplicatedStorage.Remotes
local lastSwing = {} -- player -> وقت آخر تلويحة له

-- حركات السيف الخاصة بـRoblox
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"

print("Swords deal " .. Settings.SwordDamage .. " damage")

-- تلويحة بالسيف: تُشغَّل الحركة، ثم يُصاب كل من داخل الصندوق أمامك
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
	character.Humanoid.Animator:LoadAnimation(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
			humanoid:TakeDamage(Settings.SwordDamage)
			print(humanoid.Parent.Name .. " is at " .. humanoid.Health)
		end
	end
end

-- يطلب العميل قدرةً باسمها
remotes.Ability.OnServerEvent:Connect(function(player, name)
	print(player.Name .. " asked for " .. name)
end)

-- يحصل كل لاعب على سيف في كل حياة
Players.PlayerAdded:Connect(function(player)
	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)

جميع دروس لعبة Roblox: ساحة القتال

تدرّب بنفسك: Playground لـ Roblox