Help with Pathfinding AI

  1. What do you want to achieve? Keep it simple and clear!
    I want to fix my Pathfinding AI.

  2. What is the issue? Include screenshots / videos if possible!
    My NPC’s movement seems janky and slow after working for a minute or two.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I have searched through the devforum and even used AI, but I have not found a solution or solved my issue.

I am using both a module script and a server script in order to run this code

Module Script:

local SoundDetector = {}
local RunService = game:GetService("RunService")
local maxDetectionRange = 200 -- Max range
local minDistanceChange = 3 
local checkInterval = 0.3 
local npc = nil 
local lastPosition = nil

function SoundDetector.SetNPC(character)
	npc = character
end

function SoundDetector.GetLoudestSound()
	task.wait(checkInterval)
	local loudestSound = nil
	local loudestVolume = 0

	for _, sound in pairs(workspace:GetDescendants()) do
		if sound:IsA("Sound") and sound.Playing and sound.Parent:IsA("BasePart") then
			local soundPosition = sound.Parent.Position
			local distanceToSound = (npc.HumanoidRootPart.Position - soundPosition).Magnitude
			if distanceToSound > maxDetectionRange or distanceToSound > sound.MaxDistance then continue end -- Ignore out-of-range sounds

			local effectiveVolume = (sound.Volume * (sound.MaxDistance - distanceToSound)) / (distanceToSound^2 + 1)
			if effectiveVolume > loudestVolume then
				loudestSound = sound
				loudestVolume = effectiveVolume
			end
		end
	end

	if loudestSound and (not lastPosition or (lastPosition - loudestSound.Parent.Position).Magnitude > minDistanceChange) then
		lastPosition = loudestSound.Parent.Position
		return loudestSound
	end
	return nil
end

return SoundDetector

Server Script:

local PathfindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")
local SoundDetector = require(script:WaitForChild("SoundDetector"))

local npc = script.Parent
local humanoid = npc:FindFirstChildOfClass("Humanoid")
local movingToSound = false
local wandering = false
local stuckCounter = 0
local lastMoveTime = 0

if not humanoid then
	warn("No humanoid found!")
	return
end

SoundDetector.SetNPC(npc)

local function moveToSound(sound)
	if movingToSound or wandering or not humanoid or tick() - lastMoveTime < 2 then return end
	movingToSound = true
	wandering = false
	lastMoveTime = tick()
	print("Moving to sound at:", sound.Parent.Position)

	task.spawn(function()
		local soundPosition = sound.Parent.Position
		local path = PathfindingService:CreatePath({
			AgentRadius = 2,
			AgentHeight = 5,
			AgentCanJump = true,
			AgentJumpHeight = 15,
			AgentMaxSlope = 50,
		})

		local success, errorMessage = pcall(function()
			path:ComputeAsync(npc.HumanoidRootPart.Position, soundPosition)
		end)

		if not success then
			warn("Error computing path: " .. errorMessage)
			movingToSound = false
			return
		end

		if path.Status == Enum.PathStatus.Success then
			stuckCounter = 0 -- Reset stuck counter
			for _, waypoint in ipairs(path:GetWaypoints()) do
				if not movingToSound then return end
				humanoid:MoveTo(waypoint.Position)
				local reached = humanoid.MoveToFinished:Wait(4)
				if not reached then
					warn("MoveTo failed or took too long, recalculating...")
					stuckCounter = stuckCounter + 1
					if stuckCounter >= 3 then
						warn("NPC stuck, stopping movement.")
						task.wait(2)
						stuckCounter = 0
					end
					break
				end
			end
		else
			warn("No path found to the sound.")
		end

		task.wait(1.5)
		movingToSound = false
	end)
end

local function wander()
	if wandering or movingToSound or not humanoid or tick() - lastMoveTime < 2 then return end
	wandering = true
	lastMoveTime = tick()
	print("Wandering...")

	task.spawn(function()
		while wandering do
			local randomDirection = Vector3.new(math.random(-50, 50), 0, math.random(-50, 50))
			local wanderPosition = npc.HumanoidRootPart.Position + randomDirection
			local path = PathfindingService:CreatePath({
				AgentRadius = 2,
				AgentHeight = 5,
				AgentCanJump = true,
				AgentJumpHeight = 15,
				AgentMaxSlope = 50,
			})

			local success, errorMessage = pcall(function()
				path:ComputeAsync(npc.HumanoidRootPart.Position, wanderPosition)
			end)

			if success and path.Status == Enum.PathStatus.Success then
				for _, waypoint in ipairs(path:GetWaypoints()) do
					if not wandering then return end
					humanoid:MoveTo(waypoint.Position)
					local reached = humanoid.MoveToFinished:Wait(4)
					if not reached then
						warn("MoveTo failed or took too long, recalculating...")
						break
					end
				end
			end

			task.wait(math.random(5, 8))
		end
	end)
end

RunService.Heartbeat:Connect(function()
	if movingToSound then return end

	task.spawn(function()
		local sound = SoundDetector.GetLoudestSound()
		if sound then
			print("Sound detected, switching to move mode")
			moveToSound(sound)
		else
			print("No sound detected, continuing to wander")
			--wander()
		end
	end)
end)

Any help is appreciated! Thank you!

i messed around and i actually solved it by just setting the networkownership of the primarypart to nil

2 Likes

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