I doubt a touched event can run so much that calling an empty function creates lag. I could see it happening with thousands of parts colliding in a ball, but the physics would create lag before the event would. I could also see networking causing lag in some circumstances.
It’d be easier to figure out what is going on if we had a minimal place file to examine, otherwise I’ll have to ask you a lot of questions. Is the touched event being run in a server or local script? Does the server or client own the NPCs when they are far, and which owns them when a client is near and you see lag?
Could you run this script in your place:
_G.touchCount = 0
local lastRun = tick()
while wait(1) do
local t = tick()
print('Touch count this second is:', _G.touchCount)
print('Elapsed Time: %s', t - lastRun)
_G.touchCount = 0
lastRun = tick() -- Don't include time spent printing
end
And use this touch callback:
local function onTouched()
_G.touchCount = _G.touchCount + 1
end
script.Parent.Touched:Connect(onTouched)
and report the touch count and elapsed time for a couple seconds before and after you get near a NPC?
To get an idea of roughly how many events can fire with an empty function per a second, run this script in an empty place:
local event = Instance.new 'BindableEvent'
event.Parent = workspace
event.Event:Connect(function() end)
local qty = 10 -- Start at 10 fires every 1/30th of a second (300 fires/s)
while true do
local start = tick()
for i = 1, 30 do
wait()
for j = 1, qty do
event:Fire()
end
end
local elapsed = tick() - start
print(('Rate: %d fire/second'):format(30 * qty))
print('Elapsed:', elapsed)
if elapsed >= 4 then -- ( <= 15 FPS )
break
end
qty = qty * 2
end
print 'Stopped test due to lower than 15 FPS'
It will print the current rate every second, along with how many seconds have actually passed. Since wait() stops your script until the next frame Lua is run, at 60 FPS the script will run 30 times a second. If it takes longer to accomplish 30 iterations, then the frame rate has dropped below 60 FPS. So, I think the Elapsed time is a good measure of lag. I’ve added a safety stop in case you stay in the game too long. It’ll stop after running four seconds with less than 15 frames a second.