Hello! I’m trying to script a custom explosion with particles, but I’m having a problem calculating if a humanoid is in the blast radius. What would be the best way to script this?
The only way I could think of is by creating an invisible part and sizing that to the blast radius and creating a touched event, but is there a better way? The only reason I don’t want to use this is because of it potentially blocking raycasts.
How about using the .magnitude function to calculate the distance between the Humanoid and the blast? (assuming that the blast is originating from a Part)
I think that measuring distance is usaully like this:
local function razdalja(pos1, pos2)
local distance = (pos1 - pos2).Magnitude
end
However I have never tested this out, but I created a script that calculates distance in studs:
while wait(3) do
local x1 = blue.CFrame.X
local x2 = game.Players.nuttela_for1me.Character:WaitForChild("UpperTorso").CFrame.X
local z1 = blue.CFrame.Z
local z2 = game.Players.nuttela_for1me.Character:WaitForChild("UpperTorso").CFrame.Z
local y1 = blue.CFrame.Y
local y2 = game.Players.nuttela_for1me.Character:WaitForChild("UpperTorso").CFrame.Y
local x = 0
local z = 0
local y = 0
if (x1 > 0 and x2 < 0) or (x1 < 0 and x2 > 0) then
x = math.pow(math.abs(x1 + x2), 2)
else
x = math.pow(math.abs(math.abs(x1) - math.abs(x2)), 2)
end
if (z1 > 0 and z2 < 0) or (z1 < 0 and z2 > 0) then
z = math.pow(math.abs(math.abs(z1) + math.abs(z2)), 2)
else
z = math.pow(math.abs(math.abs(z1) - math.abs(z2)), 2)
end
if (y1 > 0 and y2 < 0) or (y1 < 0 and y2 > 0) then
y = math.pow(math.abs(math.abs(y1 + y2)), 2)
else
y = math.pow(math.abs(math.abs(y1) - math.abs(y2)), 2)
end
local diagonala = math.pow(math.sqrt(x + z), 2)
local distance = math.sqrt(diagonala + y)
warn(distance)
end
local distance = Player:DistanceFromCharacter(explosion.Position) -- Assuming there's a part at where the explosion is
if distance <= 6 then
-- deal damage
end
The “distance” would be returned in studs. Although, you would need to run the above script for all players, which I think could be done using “for i, v in pairs(game.Players:GetPlayers()) do”.
Idk if you have fixed this by now but I just coded a custom explosion by making a circle part that is my blast radius. The part’s CanCollide = false and it is anchored. When I instantiate the blast radius part I add it to my “ExplosionGroup” collision group which is set not to collide with default (idk if this part matters for you but it breaks my custom player grounded check if I do not) or any other collision group for that matter. Then, here’s the part that makes it come together, I connect a function to explosion.Touched which creates a Touch Interest which allows me to detect touching parts through code even though CanCollide is false. It looks something like this:
explosion.Touched:Connect(function()
for index, value in ipairs(explosion:GetTouchingParts()) do
-- Each value is a part in the blast radius. This block is where I act on those values.
end
end)
Edit: I realized how wack this solution is and how it requires a lot of hacky solutions to get around things. I am working on a solution and I will update my response when I make my explosion better.
For now, I’m just calculating the distance between each humanoid and the explosion (since I only need to do dmg to humanoids and not actually blast stuff away). This is looping through each child of workspace. Region3 could have also worked, but then again its also just looping through each child of workspace.
Something like this: if (HumanoidRootPart.Position - explosion.Position).magnitude < 20 then “do dmg”
I could have used a giant part and use the touched event, but it could potentially mess with your target if your aiming with a weapon.
I worked on my solution a bit and it seems to have the correct hitbox without having to check through all the players and it applies effects correctly to parts without humanoids now that I added a debounce list but I can’t get it to act on humanoids quite yet. If I can fix it this method might be an upgrade but idk yet. I can bring the final version to you when I have it fixed if you like.
Sorry to spam, I thought it would take longer, but here is my custom explosion code.
All it does right now is apply knockback to the player and it certainly isn’t perfect, but the hitbox is nice thanks to the explosion part’s spherical shape. If it needs anything right now it would definitely be to spawn the center of the explosion where the explosive and the part it hit make contact rather than just the center of the explosive. But that may not apply to what you are doing. Here is my code. You are going to want to trim the parts that are specific to my game off but I wrote comments to help.
-- Rocket collides with object
body.Touched:Connect(function(hit)
if not hit:IsDescendantOf(settings.owner) then -- Make sure object is not a descendent of the owner (don't blow yourself up)
local explosion = Instance.new("Part"); -- The following would be good thrown into a module script to call explosions anywhere.
explosion.Parent = script.Parent -- Need the parent to find the body of the explosive
explosion.Shape = Enum.PartType.Ball;
explosion.Size = Vector3.new(settings.radius, settings.radius, settings.radius);
explosion.Transparency = 0;
explosion.CanCollide = false;
explosion.Anchored = true;
explosion.CFrame = body.CFrame;
explosion.BrickColor = BrickColor.new(Color3.new(255, 0, 0));
explosion.Material = Enum.Material.Neon;
game.Debris:AddItem(body, 10);
body:remove();
physicsService:SetPartCollisionGroup(explosion, "ExplosionGroup");
local connection
local active = true;
local function onTouch(hit)
if active == false then
return
end
local debounce = {}
for index, value in ipairs(explosion:GetTouchingParts()) do
-- Each value is a part in the blast radius. This block is where I act on those values.
local player = game.Players:GetPlayerFromCharacter(value.Parent)
-- Table of debounce to make sure parts are only affected once
if player ~= nil and table.find(debounce, player) == nil then
table.insert(debounce, player)
-- Do thing
local hrp = player.Character:WaitForChild("HumanoidRootPart")
local mc = player.Character:WaitForChild("MainControl")
local addVel = (-1*(explosion.Position - hrp.Position).Unit*settings.damage) * settings.kb;
print(addVel)
local args = {addVel}
remotes.knockBack:FireClient(player, args)
--hrp.Velocity = hrp.Velocity + addVel;
end
end
active = false
end
-- This triggers the explosion and allows us to tell what is touching it even with CanCollide set to false.
connection = explosion.Touched:Connect(onTouch);
wait(0.1)
game.Debris:AddItem(explosion, 10);
explosion:remove();
end
end)