How can I avoid my event firing multiple times?

I am currently using the ZonePlus module to detect when NPC’s enter an attack range, and the amount of NPCs are determined at run time and they are not a predetermined amount. I tried using a for loop to loop through the folder containing all the enemies. The issue is, whenever the enemy enters the zone, it fires an event more times than it should. Currently, there are 7 enemies in the folder for testing purposes, and the event is fired 7 times. If I lower/increase this number, that changes too.

local zone = require(game.ServerScriptService.Modules.Main.Zone)
local attackRange = zone.new(script.Parent)

local enemies = workspace.Placing.Enemies

local code = script.Parent.Parent.Code.Value
local change = game.ServerStorage.Events.TableChanged

local isRunning = false

local damage = script.Parent.Parent:GetAttribute("Damage")
local hitDelay = script.Parent.Parent:GetAttribute("HitDelay")

local queue = {}

for i,v in ipairs(enemies:GetChildren()) do 
	if v:IsA("Model") then
		local tracked = attackRange:trackItem(v)
		
		attackRange.itemEntered:Connect(function(tracked)
			local number = tonumber(tracked.Name)
			queue[number] = enemies[number]
			change:Fire(code)
		end)
		
		attackRange.itemExited:Connect(function(tracked)
			queue[tonumber(tracked.Name)] = nil
		end)
	end
end

local function largestIndex(t)
	local largest = -math.huge
	for k in pairs(t) do
		if k > largest then
			largest = k
		end
	end

	return largest
end

change.Event:Connect(function(c)
	print('event')
	if not isRunning and c == code then 
		isRunning = true

		local newest = enemies[largestIndex(queue)]

		if newest then 
			while true do
				local isWithinZoneBool, touchingZoneParts = attackRange:findItem(newest)
				
				if newest.Humanoid.Health > 0  and isWithinZoneBool then
					newest.Humanoid:TakeDamage(damage)

					task.wait(hitDelay)
				else
					break
				end
			end

			isRunning = false
		end
	end
end)

1 Like

What code exactly is running more than it should?

I would try putting the code into a function then returning true or false.

When the code is returned true then fire the event.

1 Like
for i,v in ipairs(enemies:GetChildren()) do 
	if v:IsA("Model") then
		local tracked = attackRange:trackItem(v)
		
		attackRange.itemEntered:Connect(function(tracked)
			local number = tonumber(tracked.Name)
			queue[number] = enemies[number]
			change:Fire(code)
		end)
		
		attackRange.itemExited:Connect(function(tracked)
			queue[tonumber(tracked.Name)] = nil
		end)
	end
end

This loop is firing the change event more times than it should

2 Likes

I would need to put the code into the for loop, whichll probably return the same issue. I’l try it out though :slight_smile:

1 Like

What if you added a break after this?

1 Like