Eventual slowdown due to script (RunService)

Hmm…

I’ve had a very similar issue when raycasting on a loop or anything alike.

I’m thinking maybe since the function beeline() is being called multiple times (?) it’s connecting the Heartbeat event every time it runs, creating multiple instances of that function running at once, which eventually slows down the entire game.

Perhaps try disconnecting the RunService.Heartbeat function after it’s done running?

Or try to rewrite your code to only use RunService.Heartbeat instead of an additional function called every time you want to run that snippet. (could be inefficient)

1 Like

Beeline is only called once, so I don’t believe that’s the issue.

Try suppressing the result variable or anything that addresses it, in other words, eliminate the raycast and run your test again.

The debounce works. It’s a gradual slowdown so if it was an issue, then it would be frozen or near unplayable right at the start.

1 Like

Actually, do any of you guys have experience with Humanoid:MoveTo()? After some more testing, I believe that may be the root, I ran around in circles for a while - lo and behold, lots of stutters. But then I stopped moving and the server perfomance went back to normal.

1 Like

Humanoid:MoveTo() doesn’t work on user-controlled characters, it gets overriden by the a script in StarterPlayerScripts, so if you stopped moving and it went back to normal it has to be a function detecting player movement, not controlling it.

Unless, of course, I understood that wrong.

2 Likes

Could you show your MoveTo() code?

1 Like

Sorry, I meant the Humanoid:MoveTo() in the beeline() function. Perhaps the cause is Humanoid:MoveTo() costing more resources if I do more complicated things than walking in a straight line. Pair that with the target spinning around the humanoid and I guess that is enough to lag out the server.

1 Like

It’s just the default roblox Humanoid:MoveTo().
https://developer.roblox.com/en-us/api-reference/function/Humanoid/MoveTo

Try using Humanoid.MoveToFinished before raycasting / using :MoveTo() again.

Probably because you are trying to move the character every single frame.

Remember that .Heartbeat creates a new thread every single frame. You should instead use a while loop (which yields) and add

thisHumanoid.MoveToFinished:Wait()

right below :MoveTo()

1 Like

Ah, I see. I’ll try that out. I didn’t actually know that .Heartbeat creates a new thread every single frame…

1 Like

Just use one single connection, or have a variable that says if it’s running. The code is running multiple times per frame and connecting a needles number of events.

A proper fix would be to just… not do this and have a single connection to Heartbeat instead of connecting it everytime, but an easy fix is making the chase variable global (put it at the top of the script) and putting the following at the top of the function call;

if chase and chase.Connected then
    return
end

It’ll connect to Heartbeat only if it’s not already, as it’s properly disconnected in the code

And is nil until the first call to beeline.

Beeline is called once (so then chase is connected only once), so I’m not sure if it’s creating the problem you described. I’ll keep your advice in mind for the future though.

Edit: Maybe I should make that clear in the first post.

Then the NPC will only move towards the player in a beeline once in the whole time it’s spawned, I’m certain it’s called when the NPC sees the player rather than once in it’s whole lifespan.

Try putting a print at the top of the function just to make sure. If it’s truly only being called once in it’s whole lifespan, then beeline shouldn’t be causing any performance issues.

It’s because I’m still testing the script out. I wrote the function and then immediately tested the logic out, it’s as barebones as can be. So for testing purposes, I’m fine for calling it only once as it will keep following me until it loses sight (in that case it would then stop and never move again.)

local function beeline()
	--local lastCheck = tick() - CHECK_INTERVAL
	--if tick() - lastCheck <= CHECK_INTERVAL then continue end -- only check couple times per second to increase perfomance
	--lastCheck = tick()
	while true do
		local target = getTarget()

		-- try to raycast to target
		local origin = caster.Position
		local direction = (target - origin).unit * 1000
		local result = workspace:Raycast(origin, direction, params)

		if result then
			local hitPart = result.Instance

			if hitPart:IsAncestorOf(characterFOL) ~= nil then -- check if player
				thisHumanoid:MoveTo(target)
			end
		end
		
		thisHumanoid.MoveToFinished:Wait()
	end
end

I think this worked, I believe my old code was just pretty inefficient. I do have a strange problem with the humanoid just stop working after it catches up to me (Even though I don’t have a break!) which is rather odd, but since that’s not part of the original problem I’ll try to fix it myself.

So in the end I think it was just some bad code. I’ll mark your suggestion as the solution for now unless something pops up. Thanks, all of you!

1 Like

Check if getTarget() returns nil.

It just stops printing. I haven’t seen a nil in the print statements.

The gist of the getTarget() function is that it loops through a folder in the workspace that contains all the character models. Then it finds the character with the shortest distance to the humanoid.

I believe the root of this new problem is explained here,

Anyway, thanks for helping for on the original problem. I’m going to go to bed now, it’s quite late. Thanks!

1 Like