So, I want to make this damage script code to be able to hit multiple players/NPCs however it will only choose one player/NPC, I’ve tried looking for tutorials to help me solve this but I had no luck in doing so.
Here’s the code:
script.Parent.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") ~= nil and hit.Parent then
if hit.Parent.Name == script.Player.Value or hit.Parent.Parent.Name == script.Player.Value then return end
script.Disabled = true
hit.Parent.Humanoid:TakeDamage(script.DamageTaken.Value)
local folder = workspace:FindFirstChild("DebrisFolder") or Instance.new("Folder",workspace)
folder.Name = "DebrisFolder"
local function effect()
local bolt = Instance.new("Part",folder)
bolt.Name = "Effect"
bolt.BrickColor = BrickColor.new("Cyan")
bolt.Material = "Neon"
bolt.Transparency = 0
bolt.Size = Vector3.new(0.1,0.1,0.1)
bolt.CanCollide = false
bolt.Anchored = false
bolt.CFrame = hit.CFrame
local Movement = Instance.new("BodyVelocity",bolt)
Movement.Velocity = Vector3.new(math.random(-30,30),math.random(-30,30),math.random(-30,30))
Movement.P = math.random(10,20)
game.Debris:AddItem(bolt,1)
end
for i = 1,10 do
effect()
end
end
end)
This should work, not sure as I have not tested it.
local PlayersHit = {} -- Create Table to store each player hit
script.Parent.Touched:Connect(function(hit)
local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
if table.find(PlayersHit, player.UserId) then -- check if player is in table
return
end
-- // your code here
table.insert(PlayersHit, player.UserId) -- insert player into the table
delay(1, function() -- using delay to prevent yielding the whole script.
local Index = table.find(PlayersHit,player.UserId)
table.remove(PlayersHit,Index) -- remove player from table so he can gain damage again.
end)
end)
local alreadyHit = {}
script.Parent.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") ~= nil and hit.Parent then
for i, v in ipairs(alreadyHit) do if v == hit.Parent then return end end
if hit.Parent.Name == script.Player.Value or hit.Parent.Parent.Name == script.Player.Value then return end
hit.Parent.Humanoid:TakeDamage(script.DamageTaken.Value)
table.insert(alreadyHit, v)
local folder = workspace:FindFirstChild("DebrisFolder") or Instance.new("Folder",workspace)
folder.Name = "DebrisFolder"
local function effect()
local bolt = Instance.new("Part",folder)
bolt.Name = "Effect"
bolt.BrickColor = BrickColor.new("Cyan")
bolt.Material = "Neon"
bolt.Transparency = 0
bolt.Size = Vector3.new(0.1,0.1,0.1)
bolt.CanCollide = false
bolt.Anchored = false
bolt.CFrame = hit.CFrame
local Movement = Instance.new("BodyVelocity",bolt)
Movement.Velocity = Vector3.new(math.random(-30,30),math.random(-30,30),math.random(-30,30))
Movement.P = math.random(10,20)
game.Debris:AddItem(bolt,1)
end
for i = 1,10 do
effect()
end
end
end)
Should work.
Also this assumes aoe hitbox eventually gets removed, if not just use a delayed function to clear the alreadyHit table or something idk.
I’d reccommend going with a fixed version of @ShaShxa’s code cause its a more cleaned up version of your script
task.delay(1, function()
task.wait(1) -- wait 1 second before deleting the entry
local Index = table.find(PlayersHit,player.UserId)
table.remove(PlayersHit,Index)
end)
use ipairs for this, as pairs is meant to be used on dictionaries.
The thread will still continue after the check, even if there isn’t a player as the rest of the code is not within this if statement.
Edit: sorry if this post came off as overly-stern, I’m really tired right now
Oops! I meant to write task.delay! I’m not 100% which is better, or if they are equal, but on just a use stand point, what you are doing is delaying a function, therefore I would use task.delay
local PlayersHit = {} -- Create Table to store each player hit
script.Parent.Touched:Connect(function(hit)
if game:GetService("Players"):GetPlayerFromCharacter(hit.Parent).UserId then
local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent).UserId
else
local player = 0
end
if table.find(PlayersHit, player) then -- check if player is in table
return
end
-- // your code here
table.insert(PlayersHit, player) -- insert player into the table
delay(1, function() -- using delay to prevent yielding the whole script.
local Index = table.find(PlayersHit,player)
table.remove(PlayersHit,Index) -- remove player from table so he can gain damage again.
end)
end)
Sorry with the quality of the drawing; The red lines represent the raycast while the yellow represents the Attack Of Effect.
GetPartBoundsInBox is similar to Region3 imo;
You need to use rays to get the collision hit position, once you receive the data you use GetPartBoundsInBox with (CFrame.new(Raycast.Position), HitboxSizeVector3, OverlapParams).
HitboxSizeVector3 is the hitbox size using Vector3, you can see in the drawing I use a vertical rectangle! OverlapParams is the equivalent of RaycastParams, but a little different due to not having the IgnoreWater bool that RaycastParams has.
local Results = workspace:GetPartsBoundsInBox(CFrame.new(Raycast.Position), HitboxSizeVector3, OverlapParams)
GetPartBoundsInBox returns a table/array of the objects/parts it retrieved with the HitboxSizeVector3 and CFrame.new(Raycast.Position).
Since it’s a array, you might want to use pairs to loop through the table!
Example:
for i, obj in pairs(`GetPartBoundsInBox Array/Table`) do
if obj:IsA("BasePart") and obj.Parent ~= nil and obj.Parent:FindFirstChildOfClass("Humanoid") then
-- Hit a player or a enemy!
else
-- Wall or part collision!
end
end
Sorry for the late reply once more, I just need to know if this is similar to how the code would look?
local DamageDealer = script.Parent
local PeopleHit = {}
local HitboxSizeVector3 = Vector3.new(DamageDealer.Size)
local Results = workspace:GetPartsBoundsInBox(CFrame.new(DamageDealer.Position), HitboxSizeVector3, OverlapParams)
for i, obj in pairs(PeopleHit) do
if obj:IsA("BasePart") and obj.Parent ~= nil and obj.Parent:FindFirstChildOfClass("Humanoid") then
print(PeopleHit)
end
end