Npc moving erratically

  1. What do you want to achieve? Keep it simple and clear!
    I have an npc and I used gnomecode’s tutorial on making a piggy-like monster which goes to waypoints but also chases someone if it sees it, and i (originally) edited it a bit so it’s speed increased when it saw someone, etc
  2. What is the issue? Include screenshots / videos if possible!
    a disturbance in the ministry [demo] - Roblox Studio 2022-12-20 21-56-14_Trim
    The npc moves very weirdly when it sees someone and struggles to follow it/keeps losing the person even if its standing still, im very limited in my understanding of this kind of scripting so i have no idea why it does this, but it only struggles when its trying to chase someone and otherwise moves fine to the waypoints
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried skipping waypoints and changing network ownership, walkspeed, and just using the script completely unedited except for the height and radius and yet it still does this (the navigation mesh as far as im aware looks fine?)
2 Likes

From my experience, the Pathfinding service that Roblox provides tends to be somewhat unreliable when the NPC attempts to navigate through areas that include narrow corridors and tight spaces.

Could you test real quick whether the issue reoccurs outside of the maze, preferably in an open area?

just checked, it doesn’t happen in an open area

You also specified that the erratic behaviour only occurs when the NPC is chasing a player. Would you mind posting a snippet of the relevant code so I could gain a better understanding of what the algorithm is doing in the background?

When chasing a player, I’d switch to direct following, and then switch back to pathfinding when the player is out of direct range

Use SimplePath, this module will save you time and effort as it handles the scary pathfinding stuff for you.

It is insanely smooth, I use it for all my AIs.

local function findTarget()
	local players = game.Players:GetPlayers()
	local maxDistance = 55
	local nearestTarget
	
	for index, player in pairs(players) do
		if player.Character then
			local target = player.Character
			local distance = (Terzo.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
			
			if distance < maxDistance and canSeeTarget(target) then
				nearestTarget = target
				maxDistance = distance
			end
		end
	end
	
	return nearestTarget
end

local function attack(target)
	Terzo.Humanoid.WalkSpeed = 16
	local distance = (Terzo.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude

	if distance > 4 then
		humanoid:MoveTo(target.HumanoidRootPart.Position)
	else
		Terzo.Humanoid.WalkSpeed = 10
		local attackAnim = humanoid:LoadAnimation(script.Attack)
		attackAnim:Play()
		target.Humanoid.Health = 0
	end
end

I took a look at gnomecode’s code within the video, and I was wondering how your code determines when to check for the targets in its vicinity and target them accordingly. Usually, you would expect there to be a loop to keep the coordinates of the player constantly updated provided they meet the conditions to initiate/continue a chase, but that is not the case here.

So I can only assume this loop is located elsewhere, and that loop likely keeps calling upon the attack(target) function. Could you post this loop for us?

i think it’s this im not sure though


local function walkTo(destination)
	Terzo.HumanoidRootPart:SetNetworkOwner(nil) 
	local path = getPath(destination)
	
	if path.Status == Enum.PathStatus.Success then
		for index, waypoint in pairs(path:GetWaypoints()) do
			local target = findTarget()
			if target and target.Humanoid.Health > 0 then
				print("seen", target.Name)
				attack(target)
				break
			else
				print("Moving to ", waypoint.Position)
				humanoid:MoveTo(waypoint.Position)
				humanoid.MoveToFinished:Wait()
			end
		end
	else
		humanoid:MoveTo(destination.Position - (Terzo.HumanoidRootPart.CFrame.LookVector * 20))
	end
end

I think I might see the problem.

Since there is no loop within attack(target) to keep the NPC continuously chasing the player, the algorithm returns back to the walkTo(destination) function and executes a break command. This causes the algorithm to compute a new path before calling the walkTo(destination), and since the player will likely still be in the vicinity, it will also call upon attack(target) and thus putting the NPC in a bit of a stalemate in regards to which position it should move towards.

Try the following code…

local function attack(target)
	Terzo.Humanoid.WalkSpeed = 16
	local distance = (Terzo.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
	local maxDistance = 55
	
	while target and distance < maxDistance and canSeeTarget(target) do
        distance = (Terzo.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
		if distance > 4 then
			humanoid:MoveTo(target.HumanoidRootPart.Position)
		else
			Terzo.Humanoid.WalkSpeed = 10
			local attackAnim = humanoid:LoadAnimation(script.Attack)
			attackAnim:Play()
			target.Humanoid.Health = 0
			break
		end
        wait(0.01)
	end
end

I have introduced a while loop which should be able to continuously update the humanoid:MoveTo() with the position of the player until the player no longer exists, the player exceeds the maximum distance from the NPC, or the NPC can no longer see the player. This should hopefully fix the aforementioned stalemate.

that fixed it, thank u so much ! i thought that was the issue but i didnt know how to go about fixing it lol, thank u again

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.