Menu
CoddyTech

Liên hoàn

Bài học 13 trên 25 trong khóa học Trò chơi Roblox: Đấu trường của Coddy.

Ba cú vung liên tiếp, mỗi cú cách cú trước không quá Settings.ComboWindow, tạo thành một combo: 10, 10, rồi một cú lao tới gây 25 sát thương (Settings.ComboDamage). Tạm dừng sẽ đặt lại combo.

Máy chủ ghi nhớ số cú vung liên tiếp của mỗi người chơi và thời điểm của cú vung cuối cùng:

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

c.count % 3 + 1 lần lượt cho kết quả 1, 2, 3, 1, 2, 3: sau cú lao tới, combo mới bắt đầu. Cú đánh thứ ba phát hoạt ảnh lao tới của Roblox, rbxassetid://522638767.

challenge icon

Thử thách

Trung bình

Ba cú vung kiếm nhanh tạo thành một đòn liên hoàn: 10, 10, rồi cú lao tới gây 25 sát thương.

  1. Thêm local combo = {} và Animation lunge, id rbxassetid://522638767.
  2. Trong swing, sau bước kiểm tra thời gian hồi chiêu, đếm cú vung kiếm như phần thân hàm thể hiện, kết thúc bằng c.last = now.
  3. Phát hoạt ảnh lao tới khi c.count == 3, nếu không thì phát hoạt ảnh chém; gây sát thương bằng Settings.ComboDamage[c.count].

Nhấn “Chơi” rồi vung kiếm nhanh ba lần: cú thứ ba là một cú lao tới. Sau đó nhấn “Kiểm tra”.

Tự làm thử

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

local remotes = game.ReplicatedStorage.Remotes
local lastSwing = {} -- người chơi → thời điểm vung kiếm gần nhất

-- Hoạt ảnh vung kiếm có sẵn của Roblox
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"

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

-- Mọi đòn đánh trong trò chơi đều đi qua đây
local function hurt(humanoid, amount)
	if humanoid.Health <= 0 then
		return
	end
	local character = humanoid.Parent
	-- Đỡ đòn giúp giảm phần lớn sát thương
	if character:GetAttribute("Blocking") then
		amount *= Settings.BlockMultiplier
	end
	humanoid:TakeDamage(amount)
end

-- Một lần vung kiếm: hoạt ảnh chạy, rồi mọi người trong vùng trước mặt bạn đều trúng đòn
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
	-- Bài học 13: Thêm combo vào đây
	character.Humanoid.Animator:LoadAnimation(slash):Play()
	-- Vùng trước mặt bạn, không bao gồm cơ thể bạn
	local params = OverlapParams.new()
	params.FilterDescendantsInstances = { character }
	local box = root.CFrame * CFrame.new(0, 0, -3)
	local hit = {} -- Mỗi humanoid chỉ trúng đòn một lần trong mỗi lần vung kiếm
	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.SwordDamage)
		end
	end
end

-- Các kỹ năng theo tên: chức năng của từng kỹ năng
local abilities = {}

-- Thiết bị của người chơi điều khiển nhân vật, nên thao tác lướt diễn ra trên thiết bị đó
function abilities.Dash(player)
	remotes.Ability:FireClient(player, "Dash")
end

-- Mọi người xung quanh đều trúng đòn và bị hất ra xa bạn
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

-- Máy khách yêu cầu kỹ năng theo tên. Máy chủ kiểm tra xem đó có phải kỹ năng hợp lệ,
-- kỹ năng hợp lệ, người chơi còn sống và đã hết thời gian hồi chiêu. Thời điểm kỹ năng sẵn sàng trở lại
-- là một thuộc tính (attribute) của người chơi để màn hình có thể hiển thị.
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)

-- Mỗi lần hồi sinh, người chơi nhận một thanh kiếm
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)

-- Hình nộm tập luyện: thanh máu thay đổi theo lượng máu; khi bị đánh bại,
-- hình nộm sẽ trở lại sau chốc lát dưới dạng bản sao mới ở vị trí cũ
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)

Tất cả bài học trong Trò chơi Roblox: Đấu trường

Tự luyện tập: Playground Roblox