How to stop explosions killing teammates in Roblox
A default Explosion kills every unprotected character in range, through walls. How to set DestroyJointRadiusPercent to 0 and apply your own damage in Hit.
What it looks like
A rocket, bomb or ability creates an Explosion with its default settings and lets the engine do the damage. By default an explosion breaks the joints of every character in its radius, killing them outright, whatever team, duel or safe zone they're in, and walls don't block it.
Luau
local explosion = Instance.new("Explosion")
explosion.Position = hitPosition
explosion.Parent = workspaceHow to detect it
- Find every
Instance.new("Explosion")and every cloned explosion in server code, and what triggers it. - Check
DestroyJointRadiusPercentandBlastPressure. At their defaults, every character insideBlastRadiusthat isn't protected by aForceFielddies, because the explosion breaks the character's neck joint. Joints are only broken whileBlastPressureis above 0. Team checks, friendly-fire rules, duel opponents, safe zones and damage amounts the game uses elsewhere don't apply. - Roblox's docs say obstacles don't shield anything from an explosion, so parts behind walls are hit too. A blast near a wall reaches players on the other side.
- The shape Roblox recommends is
DestroyJointRadiusPercent = 0and aHithandler that applies the game's own rules. A team check insideHitdoesn't help while the explosion still breaks joints itself. Check that handler groups parts by character, as Hit lists from the client taken as they are describes, sinceHitfires once per part. - If the explosion's position comes from the client, judge that with Hits the server doesn't check were possible too.
What an exploiter could do
Explosive weapons kill teammates, players in safe zones and players outside a duel, in one hit, through walls. With any way to trigger them faster or from further away than intended, an exploiter can clear whole areas, including spawns behind cover.
How to fix it
- Set
DestroyJointRadiusPercentto 0 on every explosion that players can cause. - Apply damage in
Explosion.Hit, once per character, using the same checks as other weapons: not the attacker's team, inside the duel, outside safe zones, andHumanoid:TakeDamagesoForceFields still protect. - If walls should block the blast, raycast from the explosion to each character before damaging them.
Vulnerable example
Vulnerable
local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Workspace = game:GetService("Workspace") local cooldown = 4 local throwRange = 60 local lastThrow: { [Player]: number } = {} ReplicatedStorage.Remotes.ThrowGrenade.OnServerEvent:Connect(function(player: Player, target: unknown) local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart") if typeof(target) ~= "Vector3" or not root or not root:IsA("BasePart") then return end if not ((target - root.Position).Magnitude <= throwRange) then return end local now = os.clock() if now - (lastThrow[player] or 0) < cooldown then return end lastThrow[player] = now local explosion = Instance.new("Explosion") explosion.Position = target explosion.BlastRadius = 10 explosion.Parent = Workspace end) Players.PlayerRemoving:Connect(function(player) lastThrow[player] = nil end)
Fixed example
Fixed
local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Workspace = game:GetService("Workspace") local cooldown = 4 local throwRange = 60 local damage = 60 local lastThrow: { [Player]: number } = {} ReplicatedStorage.Remotes.ThrowGrenade.OnServerEvent:Connect(function(player: Player, target: unknown) local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart") if typeof(target) ~= "Vector3" or not root or not root:IsA("BasePart") then return end if not ((target - root.Position).Magnitude <= throwRange) then return end local now = os.clock() if now - (lastThrow[player] or 0) < cooldown then return end lastThrow[player] = now local hit: { [Humanoid]: boolean } = {} local explosion = Instance.new("Explosion") explosion.Position = target explosion.BlastRadius = 10 explosion.BlastPressure = 0 explosion.DestroyJointRadiusPercent = 0 explosion.Hit:Connect(function(part) local character = part.Parent local humanoid = character and character:FindFirstChildOfClass("Humanoid") local victim = character and Players:GetPlayerFromCharacter(character) if not humanoid or hit[humanoid] or not victim or victim == player then return end hit[humanoid] = true if victim.Team == nil or victim.Team ~= player.Team then humanoid:TakeDamage(damage) end end) explosion.Parent = Workspace end) Players.PlayerRemoving:Connect(function(player) lastThrow[player] = nil end)
Common false positives
- Explosions that only break scenery, such as destructible walls, with no players allowed nearby, don't touch players.
- In a free-for-all game with no teams, duels or safe zones, an instant kill may be the design. Report it only if the game's other weapons deal set amounts of damage.
- Explosions created with
DestroyJointRadiusPercent = 0and damage applied inHitwith the game's own checks, like the fixed example, are fine.