Advanced NPC AI needs fixing

Greetings everyone, I’m trying to create an advanced AI, but I’ve encountered an issue.
Here’s the script:

local pathfindingservice = game:GetService("PathfindingService")
local runservice = game:GetService("RunService")
local players = game:GetService("Players")

local npc = script.Parent
local humanoid = npc.Humanoid
local head = npc.Head
local hrp = npc.HumanoidRootPart

local settings = require(npc.Settings)

hrp:SetNetworkOwner(nil)

function Patrol()
	
	print("patrol")
	
	humanoid.WalkSpeed = settings.PatrolSpeed
	
	local patrolfolder = workspace.PatrolArea:GetChildren()
	
	local randompatrol = patrolfolder[math.random(1,#patrolfolder)]
	
	local path = pathfindingservice:CreatePath(settings.agentparams)
	path:ComputeAsync(hrp.Position, randompatrol.Position)
	
	local waypoints = path:GetWaypoints()
	
	if path.Status == Enum.PathStatus.Success then
		for index, waypoint in pairs(waypoints) do
			
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
			end
			
			humanoid:MoveTo(waypoint.Position)
			humanoid.MoveToFinished:Wait()
		end
	else
		warn("Path not computed!", path.Status)
	end
	
end

function findTarget()
	local nearestTarget = nil
	local nearestDistance = math.huge

	for i,v in game.Players:GetPlayers() do
		local character = v.Character
		local humanoid = character and character:FindFirstChildOfClass("Humanoid")

		if humanoid and humanoid.Health > 0 then
			local Distance = (character.HumanoidRootPart.Position - hrp.Position).Magnitude

			if Distance < nearestDistance then
				if settings.checkTarget(character) then
					nearestTarget = v
					nearestDistance = Distance
					return nearestTarget
				end
			end
		end
	end
end

function AttackTarget(target)
	
	if target then
		-- found target
		local char = target.Character
		
		
	else
		warn("no target given.")
	end
end

function targetAngle(character)
	local npctocharacter = (character.HumanoidRootPart.Position-hrp.Position).Unit
	local npclook = hrp.CFrame.LookVector
	
	local dot = npctocharacter:Dot(npclook)
	
	local maxdist = 100
	
	local dist = (character.Head.Position-hrp.Position).Magnitude
	
	local direction = (character.Head.Position-hrp.Position)
	
	local params = RaycastParams.new()
	params.FilterDescendantsInstances = {npc, character}
	params.FilterType = Enum.RaycastFilterType.Exclude
	
	local ray = workspace:Raycast(hrp.Position, direction, params)
	
	if ray and ray.Instance then
		
		if dot > .5 then
			if dist <= maxdist then
				-- char is in fov
				return true
			else
				return false
			end
		else
			-- char is not in fov
			return false
		end
		
	else
		-- something is blocking the way
		return false
	end
end

function followTarget()
	
	local target = findTarget()
	
	if target then
		
		print("followTarget")
		
		local char = target.Character
		local charhead = char.Head
		
		local path = pathfindingservice:CreatePath(settings.agentparams)
		path:ComputeAsync(hrp.Position, char.HumanoidRootPart.Position)
		local waypoints = path:GetWaypoints()
		
		if path.Status == Enum.PathStatus.Success then
			for _, waypoint in pairs(waypoints) do
				if waypoint.Action == Enum.PathWaypointAction.Jump then
					humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
				end
				humanoid:MoveTo(waypoint.Position)
				humanoid.MoveToFinished:Wait()
			end
		else
			warn("Path not found!")
		end
		
	end
	
end

while task.wait() do
	local target = findTarget()

	if target then
		local angle = targetAngle(target.Character)
		if angle then
			followTarget()
		else
			Patrol()
		end
	else
		Patrol()
	end
end

Every function seems to work fine, but in the while loop, what seems to happen is when the NPC is patrolling, it does not chase the player. Once the patrol has reached the point, if the player meets the criteria, it chases them. Any solutions?

2 Likes

Right now when you’re calling Partol then the script Im guessing it stuck in running that function meaning it doesnt check for players nearby. I think you need to spawn the Patrol function so it can continue to look for a target and then if it finds a target then stop it from next partol checkpoint and do the attackTarget

Edit: Like the while loop at the bottom will wait for the Patrol function to return before it does another step in the loop, also when it starts attacking a target, will it ever stop attacking before reaching the last waypoint?

This is a common problem in many pathfinding AI’s. One solution could be using corountines in your script.

Gnomes code has a made a video on this displaying this problem.

I’ve tried putting it in a spawn function, but because the function does not yield, it kind of twitches towards the direction of the waypoint. So basically, when it chases it player, it faces towards the waypoint, then continues towards the direction of the player.

Thank you, I’ll be looking in to this video soon.

1 Like