Damaging the Player
Clients cannot damage other clients directly; the server needs to be responsible for issuing damage when a player is hit.
Clients can use a
RemoteEvent to tell the server that a character has been hit. These should be stored in ReplicatedStorage, where they are visible to both client and server.
- Create a Folder in ReplicatedStorage named Events.
- Insert a RemoteEvent into the Events folder and name it DamageCharacter.
- In ToolController, create variables at the start of the script for ReplicatedStorage and the Events folder.
local UserInputService = game:GetService("UserInputService") local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer) local tool = script.Parent local eventsFolder = ReplicatedStorage.Events local MAX_MOUSE_DISTANCE = 1000 local MAX_LASER_DISTANCE = 500
- Replace the
"Player hit"print statement in
fireWeaponwith a line of Lua to fire the DamageCharacter remote event with the
characterModelvariable as an argument.
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model") if characterModel then local humanoid = characterModel:FindFirstChild("Humanoid") if humanoid then eventsFolder.DamageCharacter:FireServer(characterModel) end end else -- Calculate the end position based on maximum laser distance hitPosition = tool.Handle.Position + directionVector end
The server needs to deal damage to the player who has been hit when the event is fired.
Insert a Script into ServerScriptService and name it ServerLaserManager.
Declare a variable named
LASER_DAMAGEand set it to 10, or a value of your choice.
Create a function named
damageCharacterwith two parameters called playerFired and characterToDamage.
Inside the function, find the character’s Humanoid and subtract
LASER_DAMAGEfrom its health.
damageCharacterfunction to the DamageCharacter remote event in the Events folder.
local ReplicatedStorage = game:GetService("ReplicatedStorage") local eventsFolder = ReplicatedStorage.Events local LASER_DAMAGE = 10 function damageCharacter(playerFired, characterToDamage) local humanoid = characterToDamage:FindFirstChild("Humanoid") if humanoid then -- Remove health from character humanoid.Health -= LASER_DAMAGE end end -- Connect events to appropriate functions eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
Test the blaster with 2 players by starting a local server. When you shoot the other player, their health will decrease by the number assigned to
Rendering Other Player’s Laser Beams
Currently, the laser beam is created by the client firing the weapon, so only they will be able to see the laser beam.
If the laser beam was created on the server then everyone would be able to see it. However, there would be a small delay between the client shooting the weapon and the server receiving the information about the shot. This would mean the client shooting the weapon would see a delay between when they activate the weapon and when they see the laser beam; the weapon would feel laggy as a result.
To solve this issue, every client will create their own laser beams. This means the client shooting the weapon will see the laser beam instantly. Other clients will experience a small delay between when another player shoots and a beam appears. This is the best case scenario: there is no way to communicate one client’s laser to other clients any faster.
First, the client needs to tell the server it has fired a laser and provide the end position.
Insert a RemoteEvent into the Events folder in ReplicatedStorage and name it LaserFired.
fireWeaponfunction in the ToolController script. At the end of the function, fire the LaserFired remote event using
hitPositionas an argument.
hitPosition = tool.Handle.Position + directionVector end timeOfPreviousShot = tick() eventsFolder.LaserFired:FireServer(hitPosition) LaserRenderer.createLaser(tool.Handle, hitPosition) end
The server now must receive the event that the client has fired and tell all clients the start and end position of the laser beam so they can also render it.
- In the ServerLaserManager script, create a function named playerFiredLaser above
damageCharacterwith two parameters called
- Connect the function to the LaserFired remote event.
-- Notify all clients that a laser has been fired so they can display the laser local function playerFiredLaser(playerFired, endPosition) end
-- Connect events to appropriate functions eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter) eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
The server needs the start position of the laser. This could be sent from the client, but it’s best to avoid trusting the client where possible. The character’s weapon handle position will be the start position, so the server can find it from there.
Create a function getPlayerToolHandle above the
playerFiredLaserfunction with a parameter called
Use the following code to search the player’s character for the weapon and return the handle object.
local LASER_DAMAGE = 10 -- Find the handle of the tool the player is holding local function getPlayerToolHandle(player) local weapon = player.Character:FindFirstChildOfClass("Tool") if weapon then return weapon:FindFirstChild("Handle") end end -- Notify all clients that a laser has been fired so they can display the laser local function playerFiredLaser(playerFired, endPosition)
The server can now call FireAllClients on the LaserFired remote event to send the information required to render the laser to the clients. This includes the player who fired the laser (so the client for that player does not render the laser twice), the handle of the blaster (which acts as a starting position for the laser) and the end position of the laser.
playerFiredLaserfunction, call the
playerFiredas an argument and assign the value to a variable named toolHandle.
If toolHandle exists, fire the LaserFired event for all clients using
-- Notify all clients that a laser has been fired so they can display the laser local function playerFiredLaser(playerFired, endPosition) local toolHandle = getPlayerToolHandle(playerFired) if toolHandle then eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition) end end
Rendering on the Clients
Now FireAllClients has been called, each client will receive an event from the server to render a laser beam. Each client can reuse the LaserRenderer module from earlier to render the laser beam using the tool’s handle position and end position value sent by the server. The player that fired the laser beam in the first place should ignore this event otherwise they’ll see 2 lasers.
Create a LocalScript in StarterPlayerScripts called ClientLaserManager.
Inside the script, require the LaserRenderer module.
Create a function named createPlayerLaser with the parameters
Connect the function to the LaserFired remote event in the Events folder.
In the function, use an if statement to check if
playerWhoShotdoes not equal the LocalPlayer.
Inside the if statement, call the
createLaserfunction from the LaserRenderer module using
local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local LaserRenderer = require(script.Parent:WaitForChild("LaserRenderer")) local eventsFolder = ReplicatedStorage.Events -- Display another player's laser local function createPlayerLaser(playerWhoShot, toolHandle, endPosition) if playerWhoShot ~= Players.LocalPlayer then LaserRenderer.createLaser(toolHandle, endPosition) end end eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
Test the blaster with 2 players by starting a local server. Position each client on different sides of your monitor so you can see both windows at once. When you shoot on one client you should see the laser on the other client.
The shooting sound effect currently only plays on the client that’s shooting the projectile. You’ll need to move the code to play the sound so that other players will hear it too.
- In the ToolController script, navigate to the toolActivated function and remove the line which plays the Activate sound.
local function toolActivated() if canShootWeapon() then fireWeapon() end end
- At the bottom of the
createLaserfunction in LaserRenderer, declare a variable named shootingSound and use the
toolHandleto check for the Activate sound.
- Use an if statement to check if
shootingSoundexists; if it does, call its Play function.
laserPart.Parent = workspace -- Add laser beam to the Debris service to be removed & cleaned up game.Debris:AddItem(laserPart, SHOT_DURATION) -- Play the weapon's shooting sound local shootingSound = toolHandle:FindFirstChild("Activate") if shootingSound then shootingSound:Play() end end
Previous Page Rendering the Laser Beam Next Page Securing Remotes using Validation