Ask the Server
Lesson 6 of 25 in Coddy's Roblox Game: Battlegrounds course.
Abilities start on the player's device. BattleClient is a LocalScript in the HUD. ContextActionService ties an action to keys, and with true as the third argument it also puts a button for it on a phone screen:
ContextActionService:BindAction("Wave", use, true, Enum.KeyCode.T)The function gets the action's name and the input's state, Begin when the key goes down. The server owns the rules, so the client only asks, through the RemoteEvent Remotes.Ability. On the server, OnServerEvent hears it, and Roblox passes the player who fired it first:
remotes.Ability.OnServerEvent:Connect(function(player, name)
print(name .. " from " .. player.Name)
end)Challenge
MediumMake Q ask the server for a dash.
- In
BattleClient, writeuse(name, state): onEnum.UserInputState.Begin, callremotes.Ability:FireServer(name). - Bind it:
ContextActionService:BindAction("Dash", use, true, Enum.KeyCode.Q). - In
BattleServer, connectremotes.Ability.OnServerEventtoprint(player.Name .. " asked for " .. name).
Press Play and press Q: the Output reads Player1 asked for Dash. Then Check.
Try it yourself
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)
local lastSwing = {} -- player -> when they last swung
-- Roblox's own sword animations
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"
print("Swords deal " .. Settings.SwordDamage .. " damage")
-- A swing: the animation, then everyone in the box in front of you is hit
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()
-- the box in front of you, never your own body
local params = OverlapParams.new()
params.FilterDescendantsInstances = { character }
local box = root.CFrame * CFrame.new(0, 0, -3)
local hit = {} -- each humanoid once per swing
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
-- Every player gets a sword every life
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)
-- The training dummy: its health bar follows its health, and a beaten
-- dummy comes back after a moment, a fresh copy in the same place
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)
All lessons in Roblox Game: Battlegrounds
Practice on your own: Roblox playground