Enemy NPC Doesn't Follow Player

The NPC randomly wanders around an area, until the player enters a detection radius and then it follows the player. However the NPC is meant to stop every 10 positions it wanders to. If the player enters the detection radius while the NPC is standing still, it doesn’t chase the player until it starts moving again. Just wondering why this is and if anyone can help, thanks!

Script:

local npc = script.Parent
local humanoid = npc:FindFirstChild("Humanoid")
if not humanoid then return end
if not npc.PrimaryPart then
	npc.PrimaryPart = npc:FindFirstChild("HumanoidRootPart")
	if not npc.PrimaryPart then return end
end

local spawnPos = npc.PrimaryPart.Position
local followRadius = 50
local wanderAreaSize = 20
local minDistance = 5
local forwardDistance = 2
local downwardDistance = 10
local safeDropThreshold = 2

local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {npc}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude

local wanderAnim = Instance.new("Animation")
wanderAnim.AnimationId = "rbxassetid://90572220017959"
local wanderAnimTrack = humanoid:LoadAnimation(wanderAnim)

local followAnim = Instance.new("Animation")
followAnim.AnimationId = "rbxassetid://82671911689586"
local followAnimTrack = humanoid:LoadAnimation(followAnim)

local idleAnim = Instance.new("Animation")
idleAnim.AnimationId = "rbxassetid://86102260358509"
local idleAnimTrack = humanoid:LoadAnimation(idleAnim)

local wanderDestination = nil
local isFollowing = false
local wanderPoints = 0
local reachedDestination = false

local function getWanderDestination()
	local halfSize = wanderAreaSize / 2
	local npcPos = npc.PrimaryPart.Position
	local candidate
	repeat
		local offsetX = (math.random() * wanderAreaSize) - halfSize
		local offsetZ = (math.random() * wanderAreaSize) - halfSize
		candidate = Vector3.new(spawnPos.X + offsetX, npcPos.Y, spawnPos.Z + offsetZ)
	until (candidate - npcPos).Magnitude >= minDistance
	return candidate
end

local prevPos = npc.PrimaryPart.Position

humanoid.MoveToFinished:Connect(function(reached)
	if reached and not isFollowing then
		if followAnimTrack.IsPlaying then followAnimTrack:Stop() end
		if wanderAnimTrack.IsPlaying then wanderAnimTrack:Stop() end
		if not idleAnimTrack.IsPlaying then idleAnimTrack:Play() end
	end
end)

while true do
	wait(0.1)
	local targetPlayer = nil
	local closestDistance = math.huge
	for _, player in pairs(game.Players:GetPlayers()) do
		if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
			local dist = (npc.PrimaryPart.Position - player.Character.HumanoidRootPart.Position).Magnitude
			if dist < closestDistance then
				closestDistance = dist
				targetPlayer = player
			end
		end
	end

	local npcPos = npc.PrimaryPart.Position
	local destination = npcPos

	if targetPlayer and targetPlayer.Character and targetPlayer.Character:FindFirstChild("HumanoidRootPart") then
		if closestDistance <= followRadius then
			isFollowing = true
			wanderDestination = nil
			local targetPos = targetPlayer.Character.HumanoidRootPart.Position
			destination = targetPos
		else
			isFollowing = false
		end
	else
		isFollowing = false
	end

	if not isFollowing then
		if wanderDestination == nil then
			wanderDestination = getWanderDestination()
			reachedDestination = false
		elseif (npcPos - wanderDestination).Magnitude < 1 then
			if not reachedDestination then
				wanderPoints = wanderPoints + 1
				reachedDestination = true
				if wanderPoints >= 10 then
					wait(5)
					wanderPoints = 0
				end
				wanderDestination = getWanderDestination()
			end
		else
			reachedDestination = false
		end
		destination = wanderDestination
	end

	if isFollowing then
		humanoid.WalkSpeed = 24
	else
		humanoid.WalkSpeed = 16
	end

	if isFollowing then
		humanoid:MoveTo(destination)
	elseif (destination - npcPos).Magnitude > 1 then
		humanoid:MoveTo(destination)
	end

	local currentPos = npc.PrimaryPart.Position
	local movedDistance = (currentPos - prevPos).Magnitude
	if movedDistance > 1 then
		if idleAnimTrack.IsPlaying then idleAnimTrack:Stop() end
		if isFollowing then
			if not followAnimTrack.IsPlaying then followAnimTrack:Play() end
			if wanderAnimTrack.IsPlaying then wanderAnimTrack:Stop() end
		else
			if not wanderAnimTrack.IsPlaying then wanderAnimTrack:Play() end
			if followAnimTrack.IsPlaying then followAnimTrack:Stop() end
		end
	else
		if followAnimTrack.IsPlaying then followAnimTrack:Stop() end
		if wanderAnimTrack.IsPlaying then wanderAnimTrack:Stop() end
		if not idleAnimTrack.IsPlaying then idleAnimTrack:Play() end
	end

	prevPos = currentPos
end

Thanks again!

1 Like

Solution:

local npc = script.Parent
local humanoid = npc:FindFirstChild("Humanoid")
if not humanoid then return end
if not npc.PrimaryPart then
	npc.PrimaryPart = npc:FindFirstChild("HumanoidRootPart")
	if not npc.PrimaryPart then return end
end

local spawnPos = npc.PrimaryPart.Position
local followRadius = 50
local wanderAreaSize = 20
local minDistance = 5

local wanderAnim = Instance.new("Animation")
wanderAnim.AnimationId = "rbxassetid://90572220017959"
local wanderAnimTrack = humanoid:LoadAnimation(wanderAnim)

local followAnim = Instance.new("Animation")
followAnim.AnimationId = "rbxassetid://82671911689586"
local followAnimTrack = humanoid:LoadAnimation(followAnim)

local idleAnim = Instance.new("Animation")
idleAnim.AnimationId = "rbxassetid://86102260358509"
local idleAnimTrack = humanoid:LoadAnimation(idleAnim)

local wanderDestination = nil
local isFollowing = false
local wanderPoints = 0
local reachedDestination = false
local pausedUntil = 0

local function getWanderDestination()
	local halfSize = wanderAreaSize / 2
	local npcPos = npc.PrimaryPart.Position
	local candidate
	repeat
		local offsetX = (math.random() * wanderAreaSize) - halfSize
		local offsetZ = (math.random() * wanderAreaSize) - halfSize
		candidate = Vector3.new(spawnPos.X + offsetX, npcPos.Y, spawnPos.Z + offsetZ)
	until (candidate - npcPos).Magnitude >= minDistance
	return candidate
end

local prevPos = npc.PrimaryPart.Position

humanoid.MoveToFinished:Connect(function(reached)
	if reached and not isFollowing then
		if followAnimTrack.IsPlaying then followAnimTrack:Stop() end
		if wanderAnimTrack.IsPlaying then wanderAnimTrack:Stop() end
		if not idleAnimTrack.IsPlaying then idleAnimTrack:Play() end
	end
end)

while true do
	wait(0.1)
	local currentTime = tick()

	local targetPlayer = nil
	local closestDistance = math.huge
	for _, player in pairs(game.Players:GetPlayers()) do
		if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
			local dist = (npc.PrimaryPart.Position - player.Character.HumanoidRootPart.Position).Magnitude
			if dist < closestDistance then
				closestDistance = dist
				targetPlayer = player
			end
		end
	end

	local npcPos = npc.PrimaryPart.Position
	local destination = npcPos

	if targetPlayer and targetPlayer.Character and targetPlayer.Character:FindFirstChild("HumanoidRootPart") then
		if closestDistance <= followRadius then
			isFollowing = true
			wanderDestination = nil
			destination = targetPlayer.Character.HumanoidRootPart.Position
		else
			isFollowing = false
		end
	else
		isFollowing = false
	end

	if not isFollowing then
		if currentTime < pausedUntil then
			destination = npcPos
		else
			if wanderDestination == nil then
				wanderDestination = getWanderDestination()
				reachedDestination = false
			elseif (npcPos - wanderDestination).Magnitude < 1 then
				if not reachedDestination then
					wanderPoints = wanderPoints + 1
					reachedDestination = true
					if wanderPoints >= 10 then
						pausedUntil = tick() + 5
						wanderPoints = 0
					end
					wanderDestination = getWanderDestination()
				end
			else
				reachedDestination = false
			end
			destination = wanderDestination
		end
	end

	if isFollowing then
		humanoid.WalkSpeed = 24
	else
		humanoid.WalkSpeed = 14
	end

	if isFollowing then
		humanoid:MoveTo(destination)
	elseif (destination - npcPos).Magnitude > 1 then
		humanoid:MoveTo(destination)
	end

	local currentPos = npc.PrimaryPart.Position
	local movedDistance = (currentPos - prevPos).Magnitude
	if movedDistance > 1 then
		if idleAnimTrack.IsPlaying then idleAnimTrack:Stop() end
		if isFollowing then
			if not followAnimTrack.IsPlaying then followAnimTrack:Play() end
			if wanderAnimTrack.IsPlaying then wanderAnimTrack:Stop() end
		else
			if not wanderAnimTrack.IsPlaying then wanderAnimTrack:Play() end
			if followAnimTrack.IsPlaying then followAnimTrack:Stop() end
		end
	else
		if followAnimTrack.IsPlaying then followAnimTrack:Stop() end
		if wanderAnimTrack.IsPlaying then wanderAnimTrack:Stop() end
		if not idleAnimTrack.IsPlaying then idleAnimTrack:Play() end
	end

	prevPos = currentPos
end