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 = nowc.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.
Thử thách
Trung bìnhBa 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.
- Thêm
local combo = {}và Animationlunge, idrbxassetid://522638767. - 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ằngc.last = now. - 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ằngSettings.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