AOE Ability Help

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)

.

try removing that part script.Disabled = true

Alright, I’ll try that to see if it works

Slight problem, the script now does about 5X damage to Players/NPCs

From what I understand is you are trying to damage a player once and not too much, but you also want it to hit multiple people.

Trying adding a table and insert every player that has been hit.

Then after a while (like after 1 second for example) remove the player from the table so they can be hit again.

Add a check inside of the script if the player who touched it is in the table, if not add damage.

If you need a script example, simply reply here and I will give you one.

1 Like

I would like a script example please, since I haven’t used tables much

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)

Let me now if this works.

Edit:
Fixed a typo in the code.

Optimized code, thanks @Chromatype

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

use

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 :sweat_smile:

I prefer to use corountine because it is better than delay nowadays.

You can read more here

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

When using the script against some dummies an error appeared, it said this:

Workspace.Folder.FinalStorm.Dmg:6: attempt to index nil with 'UserId'

Would you perhaps know how to fix this?

Add a check if the person hit is a player:

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)

It seems I’m getting the same error but instead of FinalStorm.Dmg:6: it’s giving me FinalStorm.Dmg:9:

Made a typo, try it out now.
(charlimit)

Are you trying to make a Area Of Effect ability?

If so, then you should use :GetPartBoundsInBox(). It is similar to Region3, but better imo

Sorry for replying very late but would you mind giving an example? I’ve never made an AOE attack before, nor have I ever used GetPartBoundInBox

An example of using GetPartBoundsInBox() is making a projectile with AOE,


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
1 Like

Replace PeopleHit with Results, the PeopleHit variable is an empty table unlike the Results variable. But yes, that’s how the code would work!