My explosions system use a distance check to deal damage depending on distance but it’s not very efficient, how can I redo it?
local Explosion = game:GetService("ServerStorage").Core.Storage.Effects.RPGEX1:Clone()
Explosion.Anchored = true
Explosion.Position = Handle.Position
Explosion.Parent = workspace.Spawned
game:GetService("Debris"):AddItem(Explosion, 4)
for _,v in game:GetService("Players"):GetPlayers() do
if v.Character then
local Character = v.Character
local PRT = Character.PrimaryPart.Position
if (PRT - Explosion.Position).Magnitude <= 3 and (PRT - Explosion.Position).Magnitude >= 6 then
Character:FindFirstChildOfClass("Humanoid"):TakeDamage(100)
end
if (PRT - Explosion.Position).Magnitude <= 6 and (PRT - Explosion.Position).Magnitude >= 12 then
Character:FindFirstChildOfClass("Humanoid"):TakeDamage(50)
end
end
end
-- Localize services once at the top.
local PlayerService = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
-- I assume the following part of the code runs when server receives a signal.
local Explosion = ServerStorage.Core.Storage.Effects.RPGEX1:Clone()
Explosion.Anchored = true
Explosion.Position = Handle.Position
Explosion.Parent = workspace.Spawned
-- task instead of Debris.
task.delay(4, function()
for _, player in ipairs(PlayerService:GetPlayers()) do
if not player.Character or not player.Character.PrimaryPart then
continue;
end
local humanoid = player.Character:FindFirstChild("Humanoid")
local rootPos = player.Character.PrimaryPart.Position
-- Store magnitude in a variable once
local magnitude = (rootPos - Explosion.Position).Magnitude
if magnitude <= 6 then
humanoid:TakeDamage(100)
elseif magnitude <= 12 then
humanoid:TakeDamage(50)
end
end
Explosion:Destroy()
end)
Performance vice, the magnitude checks are definitely on the efficient side of the spectrum, compared to other methods I can think of. Following the DRY principle (“don’t repeat yourself”) and avoiding Debris service, the code snippet seems fine.
Why not use the Debris service? It was very commonly used in the past, however, today it’s better to use the more consistent task methods. Debris implements old 30 Hz wait(), which makes it no different than old spawn() and delay() in terms of execution priority and reliability.
I hope you don’t mind me changing the if-else statements, the values seemed to contradict, so I just left some example.
Edit: Spelling and forgot to fully replace Debris by destroying the explosion at the end.
I’m very much in favor of organizing in tables, though in this case of a couple if-statements, some serious readability improvement doesn’t really seem necessary. It would maybe come useful if there were different effects, and so on, depending on the distance.
Why not use explosion.hit? You can exclude a model once it has already been hit, that way each player receives damage once rather than for each part in their character model.
I see. I would still use an explosion instance for the simplicity of it. Set visibility to false and the joint-break percentage to 0. That way you can still overlay your explosion particles on top.
It shouldn’t matter where the explosion is placed, as it gets deleted instantly after. You would create the new instance and connect a hit function to it.
local HitPlayers = {}
local Explosion = Instance.new("Explosion")
Explosion.Parent = Workspace
Explosion.Position = **Position**
Explosion.Visible = false
Explosion.DestroyJointRadiusPercent = 0
Explosion.Hit:Connect(function(part)
if part.Parent:FindFirstChild("Humanoid") then
if HitPlayers[part.Parent] == false then
**Deal Damage**
HitPlayers[part.Parent] = true
end
end
end)
Something similar to this would do. The connection should disconnect when the explosion is deleted automatically.