Thời gian chờ của máy chủ
Bài học 8 trên 25 trong khóa học Trò chơi Roblox: Đấu trường của Coddy.
Kẻ khai thác quyền kiểm soát thiết bị của chính mình, nên có thể kích hoạt Remotes.Ability hàng trăm lần mỗi giây, với bất kỳ tên nào. Thời gian hồi chiêu trong LocalScript chỉ ngăn được những người chơi trung thực: máy chủ phải thực thi giới hạn này.
Máy chủ lưu thời điểm mỗi người chơi có thể dùng lại từng kỹ năng dưới dạng thuộc tính của người chơi, bài học tiếp theo sẽ hiển thị thông tin này trên màn hình. workspace:GetServerTimeNow() là đồng hồ mà máy chủ và mọi máy khách đều thống nhất:
local now = workspace:GetServerTimeNow()
if now < (player:GetAttribute(name .. "ReadyAt") or 0) then
return
end
player:SetAttribute(name .. "ReadyAt", now + Settings.Cooldowns[name])Máy chủ cũng kiểm tra nội dung được gửi: đó phải là chuỗi chỉ tên một kỹ năng có thật, được gửi từ một người chơi còn sống.
Thử thách
Trung bìnhKhiến máy chủ từ chối những gì kẻ khai thác có thể gửi.
- Trong trình xử lý
Ability, trả về nếutypeof(name) ~= "string", kỹ năng không tồn tại hoặc người chơi không có nhân vật còn sống. - Trả về nếu
workspace:GetServerTimeNow()nhỏ hơnplayer:GetAttribute(name .. "ReadyAt")(hoặc 0). - Nếu không, đặt thuộc tính đó thành thời điểm hiện tại +
Settings.Cooldowns[name], rồi chạy kỹ năng.
Nhấn Chơi rồi nhấn Q hai lần: lần lướt thứ hai phải chờ 3 giây. 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 = {} -- player -> thời điểm vung kiếm gần nhất
-- Hoạt ảnh vung kiếm của Roblox
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"
print("Swords deal " .. Settings.SwordDamage .. " damage")
-- Một lần vung kiếm: phát hoạt ảnh, rồi đánh trúng mọi người trong vùng phía trước bạ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
character.Humanoid.Animator:LoadAnimation(slash):Play()
-- Vùng phía trước 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 nhân vật 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
humanoid:TakeDamage(Settings.SwordDamage)
print(humanoid.Parent.Name .. " is at " .. humanoid.Health)
end
end
end
-- Các kỹ năng theo tên và tác dụ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 của họ, 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áy khách yêu cầu kỹ năng theo tên; máy chủ thực hiện kỹ năng đó
remotes.Ability.OnServerEvent:Connect(function(player, name)
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if abilities[name] and root then
abilities[name](player, character, root)
end
-- Bài học 8: Thêm thời gian chờ kỹ năng trên máy chủ vào đây
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, và khi bị hạ,
-- hình nộm sẽ xuất hiện lại sau một lúc dưới dạng bản sao mới ở cùng vị trí
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
2Máy khách và máy chủ
Gửi yêu cầu đến máy chủTự luyện tập: Playground Roblox