AOE system issue

For my tower defense game, I want to make a AOE effect damage system. I did this by creating a circle, then when zombies touched it took their damage. The issue with this is that they can touch the circle multiple times, inflicting 4 damage every frame basically. I am wondering how to make zombies only take damage one time from the splash. Thanks!

1 Like

tag the zombie with attribute use it as a debounce type setup something like this might work

if not Zombie:GetAttribute('Tagged') then 
   -- could even add to this number for different times it takes damage or just set it true
   Zombie:SetAttribute('Tagged', 1)  
   -- do damage here
end

An easier solution is just using the workspace/worldroot method GetPartBoundsInRadius,
It only requires a position value and a radius, which if you’re using a sphere part to define the area then its just part.Size.X divided by 2.

Then for all the humanoidrootparts within the radius apply damage to each of them

1 Like

If you have a physical circle (I.E. a cylinder part), you can use GetPartsInPart() to detect all zombies inside the circle at a given point in time.

With this approach, you would simply do workspace:GetPartsInPart(circle, params)
Params being an OverlapParams.new() instance.

Alternatively, you could remove the need for a physical instance by using GetPartsBoundsInRadius(). This will tell you all of the parts inside a sphere of a given radius.

With this approach, you would simply do workspace:GetPartsBoundsInRadius(towerPos, radius, params)
Params being an OverlapParams.new() instance.

1 Like

As adrian and xander said, you could get parts in a radius, or you can use Magnitude to check how far from the center of your circle is. I’d only recommend it over the other methods as you can just check one parts vs getting an array of multiple parts if you’re only interested in their center part.

Its still dealing damage 24 times to 4 zombies.

for _,v in ipairs(workspace:GetPartsInPart(splash, OverlapParams.new())) do
						local parent = v:FindFirstAncestorWhichIsA('Model')
						if parent then 
							if parent:FindFirstChild('A') then
								if parent.A:FindFirstChild('Zombie') then
									print('Deal '..tostring(abs_damage))
									parent.Humanoid:TakeDamage(abs_damage)
							end
							end
						
						end

is my code.

The issue with this is that itll make so other AOE towers cant damage the same enemy.

your towers don’t have unique names or ids?

This is because the :GetPartsInPart() function returns every part. So if the zombie has both legs in the circle, both legs will show up on the table. To circumvent double damage, I’d advise you to create a temporary table containing already damaged humanoids during the current execution.

Creating a temporary array:
To do this, create a table outside of the for loop by doing DamagedEnemies = {}.

Inserting Zombie to Array:
After that, you need to write a line of code that inserts a zombie into the table when it is damaged. To do this, you would simply write table.insert(DamagedEnemies, zombie) right before the :TakeDamage() line.

Checking Temp Array:
Then finally you can add a sanity check that ties this all together. After the if zombie then conditional statement create another conditional statement. This statement will be:

if not table.find(DamagedEnemies, zombie) then -- if zombie has not been damaged yet

end

Clearing Array:
Lastly, you need to clear the table after the AOE attack. Simply do DamagedEnemies = {} after the for pairs loop. By setting DamagedEnemies to { } you are essentially resetting the array to a blank slate.

Hey, thanks for your answer! This works perfectly and another thing is what Adrian said, you can also in your loop check for there humanoidrootparts before damage. Thanks!

1 Like