Pathfinding NPC issue

Before you help me try and figure this out just know I am using SimplePath for my NPC. SimplePath - Pathfinding Module

I want my NPC to be able to move continusly without having to wait also to switch between chase and patrol states with ease. In chase mode the NPC will wait until it finishes going to the goal rather then continusioly making the player its goal. Ive tried multiple forums and youtube tutorials but still havent found a solution.

This is the code please let me know if you find any flaws or any reason as to why my NPC wont do what I want it to…

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local simplePath = require(ReplicatedStorage:WaitForChild("SimplePath"))

local NoiseEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("PlayerNoiseEvent")

local NPC = workspace:WaitForChild("BlindMonster2")
local Humanoid = NPC:FindFirstChildOfClass("Humanoid")
local NPC_Root = NPC.PrimaryPart or NPC:FindFirstChild("HumanoidRootPart")

local PatrolPoints = workspace:WaitForChild("PatrolPoints"):GetChildren()

local playerDetected = false
local patrolling = false
local activePath = nil
local patrolResetTask = nil

local maxDetectionRange = 50
local attackRange = 5
local damage = 10
local attackCooldown = 2
local lastAttackTime = 0
local pathRegen = 0.05

local patrolWaitTimeMin = 2
local patrolWaitTimeMax = 6
local resumePatrolDelay = 1

local function StopCurrentPath()
	print("stop")
	if activePath and activePath._status == "Active" then
		activePath:Stop()
	end
	activePath = nil
end

local function Patrol()
	print("patrol")
	if playerDetected then return end -- If chasing, don't patrol

	StopCurrentPath() -- Clears any existing path before starting patrol
	patrolling = true

	local randomPoint = PatrolPoints[math.random(1, #PatrolPoints)]
	local patrolPosition = randomPoint.Position

	activePath = simplePath.new(NPC)
	activePath.Visualize = true

	local success = activePath:Run(patrolPosition)
	print("path")
	if not success then
		print("no")
		patrolling = false
		task.wait(1)
		Patrol()
		return
	end

	task.spawn(function()
		while activePath and activePath._status == "Active" do
			task.wait(pathRegen)
		end
		if activePath and activePath._status == "Idle" and not playerDetected then
			task.wait(math.random(patrolWaitTimeMin, patrolWaitTimeMax))
			patrolling = false
			Patrol()
		end
	end)
end

local function ResetPatrolAfterDelay()
	print("reset patrol")
	if patrolResetTask then
		task.cancel(patrolResetTask) -- Cancels any previous reset
	end

	patrolResetTask = task.delay(resumePatrolDelay, function()
		if not playerDetected and not patrolling then
			print("Resuming patrol after losing player.") 
			Patrol()
		end
	end)
end

local function MoveToSound(soundType, position)
	print("sound")
	if not NPC_Root then return end

	local distance = (NPC_Root.Position - position).Magnitude
	if distance > maxDetectionRange then
		playerDetected = false
		return
	end

	StopCurrentPath() -- Ensures old paths are stopped before moving to sound

	playerDetected = true
	patrolling = false  

	activePath = simplePath.new(NPC)
	activePath.Visualize = true
	activePath:Run(position)
	print("path")

	if Humanoid then
		Humanoid.WalkSpeed = 22
	end

	task.spawn(function()
		while activePath and activePath._status == "Active" do
			task.wait(pathRegen)
		end
		if activePath and activePath._status == "Idle" then
			playerDetected = false
			ResetPatrolAfterDelay()
		end
	end)
end

local function AttackPlayer(player)
	print("attacked")
	if tick() - lastAttackTime < attackCooldown then return end  
	lastAttackTime = tick()

	local humanoid = player:FindFirstChildOfClass("Humanoid")
	if humanoid then
		humanoid:TakeDamage(damage)  
	end
end

NoiseEvent.OnServerEvent:Connect(function(player, soundType, position)
	print("noise")
	if playerDetected then return end -- Ignore if already chasing

	local distance = (NPC_Root.Position - position).Magnitude
	if distance > maxDetectionRange then return end

	StopCurrentPath() -- Stops patrolling if chasing starts

	MoveToSound(soundType, position)
end)

task.spawn(function()
	while true do
		task.wait(3)
		if not playerDetected and not patrolling then
			Patrol()
		end
	end
end)

3 Likes

where’s the function responsible for chasing the player???

3 Likes

It is this function I have a local script which fires when the player moves, then it finds the distance of the player then uses simplePath to do activePath:Run(position) position being the characters current location

I rewrote the script and it works now.

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