Enemy NPC not detecting players, can anyone help?

Hey there,

This NPC script works just fine on paper; it finds players and chases them as it’s supposed to. However, when I added the ‘idle()’ function and repeat loop it, for some reason, refuses to find players again. To combat this, I’ve added a boolean called ‘EnemyInSight’ - take a look for yourself, if you’d like! Any help is greatly appreciated.

I’ve already tried adding a while loop (specifically, something among the lines of “while EnemyInSight == true do”, but that also didn’t work, I’ve also searched the internet for this, but to no avail.

Again, any help is greatly appreciated! Thanks in advance.

math.randomseed(tick())

local myHuman = script.Parent:WaitForChild("Humanoid")
local myRoot = script.Parent:WaitForChild("HumanoidRootPart")
local head = script.Parent:WaitForChild("Head")
local lowerTorso = script.Parent:WaitForChild("LowerTorso")

local walkAnim = script.Parent.Walk
local walkAnimPlay = myHuman:LoadAnimation(walkAnim)

local idleAnim = script.Parent.Idle
local idleAnimPlay = myHuman:LoadAnimation(idleAnim)

local holdWeapon = script.Parent.HoldWeapon
local holdWeaponPlay = myHuman:LoadAnimation(holdWeapon)

holdWeaponPlay:Play()

local clone = script.Parent:Clone()

------- the idle animation playing
function idle()
	repeat
		idleAnimPlay:Play()
		wait(idleAnimPlay.Length)
	until script.Parent.EnemyInSight.Value == true
end


function findPath(target)
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myRoot.Position,target.Position)
	local waypoints = path:GetWaypoints()
	
	if path.Status == Enum.PathStatus.Success then
		for _, waypoint in ipairs(waypoints) do
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				myHuman.Jump = true
			end
			myHuman:MoveTo(waypoint.Position)
			local timeOut = myHuman.MoveToFinished:Wait(1)
			if not timeOut then
				myHuman.Jump = true
			--	print("Path too long!")
				script.Parent.EnemyInSight.Value = false
				findPath(target)
				break
			end
			if checkSight(target) then
				repeat
				---	print("Moving directly to the target")
			script.Parent.EnemyInSight.Value = true
					myHuman:MoveTo(target.Position)
					wait(0.1)
					if target == nil then
						break
					elseif target.Parent == nil then
						break
					end
				until checkSight(target) == false or myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
				break
			end
			if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
				--				print("Target has moved, generating new path")
			script.Parent.EnemyInSight.Value = true
				findPath(target)
				break
			end
		end
	end
end

function checkSight(target)
	local ray = Ray.new(myRoot.Position, (target.Position - myRoot.Position).Unit * 40)
	local hit,position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
	if hit then
		if hit:IsDescendantOf(target.Parent) and math.abs(hit.Position.Y - myRoot.Position.Y) < 3 then
			--print("I can see the target")
			script.Parent.EnemyInSight.Value = true
			return true
		end
	end
	return false
end

function findTarget()
	local dist = script.Parent.Distance.Value
	local target = nil
	local potentialTargets = {}
	local seeTargets = {}
	for i,v in ipairs(workspace:GetChildren()) do
		local human = v:FindFirstChild("Humanoid")
		local torso = v:FindFirstChild("Torso") or v:FindFirstChild("HumanoidRootPart")
		if human and torso and v.Name ~= script.Parent.Name then
			if (myRoot.Position - torso.Position).magnitude < dist and human.Health > 0 and human.NPC.Value == false then
				table.insert(potentialTargets,torso)
			end
		end
	end
	if #potentialTargets > 0 then
		for i,v in ipairs(potentialTargets) do
			if checkSight(v) then
				table.insert(seeTargets, v)
			elseif #seeTargets == 0 and (myRoot.Position - v.Position).magnitude < dist then
				script.Parent.EnemyInSight.Value = false
				idle()
			end
		end
	end
	if #seeTargets > 0 then
		dist = 30
		for i,v in ipairs(seeTargets) do
			if (myRoot.Position - v.Position).magnitude < dist then
				target = v
				dist = (myRoot.Position - v.Position).magnitude
			end
		end
	end
	if target then
		if math.random(20) == 1 then
			head.Quote1:Play()
			-- play sound
		end
	end
	return target
end


lowerTorso.Touched:Connect(function(obj)
	if not obj.Parent:FindFirstChild("Humanoid") then
		myHuman.Jump = true
	end
end)

function main()
	local target = findTarget()
	if target then
		myHuman.WalkSpeed = script.Parent.ChaseSpeed.Value
		idleAnimPlay:Stop()
		walkAnimPlay:Play()
		findPath(target)
	else
		myHuman.WalkSpeed = script.Parent.WanderSpeed.Value
		script.Parent.EnemyInSight.Value = false
		idle()
	end
end

while wait(0.1) do
	if myHuman.Health < 1 then
		break
	end
	main()
end

Have you tried substituting the idle loop by making it so your animation is looped (i’d recomend you reupload the animation, but make sure the Loop property is true


Then, if you have the idle animation looping what you can do is just change the idle funciton to something like

function idle()
    if idleanimation is NOT running (use the AnimationTrack.IsPlaying Property )
        stop other running animations (if necessary)
        play idle animation
   endif
endfunction

One other thing i’d recomend you do is change the condition in the while wait(0.1) do

while wait(0.1) do
	if myHuman.Health < 1 then
		break
	end
	main()
end

to

while myHuman.Health>=1 do
  main()
  wait(0.1)
end
1 Like

Hey there! Thanks for the reply. The idle animation in question is a roblox animation (you can see which one below), so I couldn’t reupload it and set the loop property to true, however, I did this in the script with this:

	idleAnimPlay.Looped = true

Thanks for the help! I’ll mark your reply as a solution, have a great day!

https://www.roblox.com/library/507766666/R15IdleLookAround

1 Like