Enemy NPC not following player correctly

EDIT: Thank you WoTrox & SubtotalAnt8185 for your help! Everything works now :heart:

  1. What do you want to achieve?
    I’m trying to make the enemy follow the player ONLY when it’s within a certain distance of the player.

  2. What is the issue?
    Currently, it doesn’t work exactly how I would like it to. When it initially spawns into the Workspace after being cloned from ReplicatedStorage it automatically runs straight for the player; however, once the player moves towards the NPC and then away, it works as I’d like it to (I think? I’m not sure if it’s exactly working).

  3. What solutions have you tried so far?
    I’ve looked at videos, the DevForum, etc. but I can’t seem to find anything that’s related to the specific problem I’m having.

Here’s a link to a model I’ve created so that you’ll be able to try it out yourself in-game!

I’d really appreciate if someone were to help me fix this error and tell me what seems to be creating the problem.

Here’s the scripts for anyone who isn’t able to use the model but still wants to help :slight_smile:

EnemyControllerScript:

local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local humanoid = script.Parent
local root = humanoid.Parent.PrimaryPart

local targetDistance = 20
local stopDistance = 5

function findNearestPlayer()
	local playerList = Players:GetPlayers()
	
	local nearestPlayer = nil
	local distance = nil
	local direction = nil
	
	for _, player in pairs(playerList) do
		local character = player.Character
		if character then
			local distanceVector = (player.Character.HumanoidRootPart.Position - root.Position)
			if not nearestPlayer then
				nearestPlayer = player
				distance = distanceVector.Magnitude
				direction = distanceVector.Unit
			elseif distanceVector.Magnitude < distance then
				nearestPlayer = player
				distance = distanceVector.Magnitude
				direction = distanceVector.Unit
			end	
		end
	end
	
	return nearestPlayer, distance, direction
end

RunService.Heartbeat:Connect(function()
	local nearestPlayer, distance, direction = findNearestPlayer()
	if nearestPlayer then
		if distance <= targetDistance and distance >= stopDistance then
			humanoid:Move(direction)
		else
			humanoid:Move(Vector3.new())
		end
	end
end)

Walking script:
(This is where I believe the problem is coming from but I’m not sure how to fix the problem as I created a custom walking animation but don’t know how else to make it work besides having another script).

local enhum = script.Parent.Humanoid
local anm = script.Parent.Humanoid.Walk
local load = script.Parent.Humanoid:LoadAnimation(anm)

while wait() do
	for i,v in pairs(game.Players:GetChildren()) do
		local character = game.Workspace:WaitForChild(v.Name)
		enhum:MoveTo(character.PrimaryPart.Position)
		load:Play()
		enhum.MoveToFinished:Wait(1)
		load:Stop()
		
	end
	end

Visual in studio:
Screen Shot 2022-06-29 at 11.43.09 AM

Thank you so much for helping out a new scripter (aka me)! :hugs:

Ok so, the problem is that you have 2 different scripts that do almost the same. The first one (EnemyController) should work fine. I (or even you) could clean it up a bit, but it should work. It finds the nearest player and walks towards it.
Now in the Walking script, you remove all of that and try to walk toward every player, not just the nearest one

(look at the comments)

for i,v in pairs(game.Players:GetChildren()) do -- gets EVERY player that is in the game
	local character = game.Workspace:WaitForChild(v.Name)
	enhum:MoveTo(character.PrimaryPart.Position) -- walks towards the player, but for every player
	load:Play()
	enhum.MoveToFinished:Wait(1) -- this 1 here wont do anything, so use just Wait() without number
	load:Stop()
		
end

The reason it walks towards you is that you’re the only player in the game, I suppose.
So just delete the Walk script, and it should work fine.
To change the default animations, copy the Animate script from your player (it’s in the character while playing), paste it into the NPC’s character, and change the animations there. Let me know if you need help.

And also, in the first script, I don’t think you should do it in the Heartbeat event, it might cause lag later.
Instead, put it in a while loop, and wait 0.5 seconds or something like that every time there is NO nearest player, and wait 0.1 every time THERE IS a player.

1 Like

I couldn’t agree more. I also don’t like this:

:GetPlayers() was right there! But I understand that you’re a new scripter.

So, the reply above should work properly. I also recommend loading animations with Animator:LoadAnimation() as Humanoid:LoadAnimation() is deprecated.

1 Like

Thank you so much for your thoughtful reply! I really appreciate it :slight_smile:

I’ve disabled the Walking script and now the following/EnemyController script works as it should—I appreciate you explaining the why to me cause it makes learning much easier.

Regarding the animations, I’m now having difficulty getting that to work after removing the Walking Script. I’ve inserted the copied Animate script from the Player and changed the Animation within the walk & run StringValues as well as the ID within the Animate Script to the animation I made but the animations aren’t working. Should it be working as soon as I put the script into the model/NPC? Or do I have to load the animation using the EnemyController Script?

Here’s some screenshots that might be helpful!
Screen Shot 2022-06-29 at 1.51.43 PM


Also for fixing the Heartbeat Event so there will be no lag, is this how I would write it?

	--*Removed RunService.Heartbeat:Connect(function()
local nearestPlayer, distance, direction = findNearestPlayer()
	while nearestPlayer do
		if distance <= targetDistance and distance >= stopDistance then
wait (0.1)
			humanoid:Move(direction)
		else
wait (0.5)
			humanoid:Move(Vector3.new())
		end
	end
end)

Thank you again, I hope I’m not bothering you too much or asking too many questions :sweat_smile:

That one is a LocalScript. It only works if it has a player.

You can use the server model instead:
Animate.rbxm (7.0 KB)

1 Like

Thank you so much for your response :slight_smile:

For the mistake I made, that’s for the EnemyController Script at line 2, correct?
So, instead of:

local Players = game.GetService("Players")

It should be:

game.Players:GetChildren()

Sorry for the stupid questions; however, I appreciate the opportunity to learn.

I also appreciate the tips regarding loading animations, I’ll make sure to use that in the future!

Not exactly. You use ‘:’ for calling functions inside of an instance.

It should probably be Players:GetPlayers(), which would be the best.

Edit: Line 2 is fine. Don’t change it.

1 Like

Thank you!

The server model you provided doesn’t seem to be working for me, do I download it and open it in Roblox Studio?

Edit: Ope, nevermind. I see that it’s a text file. I’ll see if I have a program to open it.

Edit2: Nevermind, I found how to open it in Roblox Studio, sorry.