Pathfinding AI gone wrong?

So recently, I’ve been following this new pathfinding AI tutorial on youtube (Link here) however, after working yesterday and this morning, I decided to add some additions to benefit my game.

After adding said benefits, I noticed something strange, the AI seemed like it just totally gave up on pathfinding, and now walks right into walls.

I’ve done some trouble shooting, and it turns out the the AI actually locates a correct path, but decides not to follow it. (as seen below)

I have no idea what went wrong and if someone would be able to help that would be great! thanks!
-Revelted

Code:

local rootpart = script.Parent.HumanoidRootPart
local human = script.Parent.Humanoid
_G.Table = {script.Parent}


function findtarget ()
	local distance = 75
	local target = nil
	for i,v in pairs(workspace:GetChildren())do
		local humanoid = v:FindFirstChild("Humanoid")
		local head = v:FindFirstChild("Head")
		if humanoid and head and v.Name ~= ("dude5") then
			if (head.Position - rootpart.Position).magnitude < distance and humanoid.Health > 0 then
				distance = (head.Position - rootpart.Position).magnitude
				 target = head
			end
		end
	end
	return target
	
end
while wait() do
	local head = findtarget()
	
	if head then
		local ray = Ray.new(rootpart.Position, (head.Position-rootpart.Position).Unit *200)
		local hit,position = workspace:FindPartOnRayWithIgnoreList(ray,_G.Table)
		if hit then
			if hit:IsDescendantOf(head.Parent) and hit.Parent ~= workspace then
				human:MoveTo(head.Position)
			else
				human:MoveTo(head.Position)
				wait(.4)
				path = game:GetService("PathfindingService"):FindPathAsync(rootpart.Position,head.Position)
				points = path:GetWaypoints()
				if path.Status == Enum.PathStatus.Success then
				for i,v in pairs(points) do
					
					human:MoveTo(v.Position)
					human.MoveToFinished:Wait()
					if v.Action == Enum.PathWaypointAction.Jump then
						wait()
						human.Jump = true
					
					
					end
					if (points[#points].Position - head.Position ).magnitude > 30 then
						break
					end
					
				end
				else
					human:MoveTo(head.Position)
				end
			end
		end
	end
	
end
2 Likes

I noticed that there are two possibilities of just making the Humanoid walk to head.Position in a straight line if either a ray can be drawn from initial position to destination or path.Status ~= Success. Try printing something beside those two to see if either of those are happening.
Also try printing something after every human.MoveToFinished:Wait() to see if the waits are being skipped somehow.

Use PathfindingService:CreatePath

You are using deprecated methods for PathfindingService, even though this shouldn’t really matter at all. PathfindingService has been revised multiple times, at least this year.
The current method PathfindingService has for finding paths is :CreatePath with a useful dictionary argument for agent parameters.
This creates a new Path object, which you can use :ComputeAsync on with the initial position and destination to compute the path. After this is done, you can call :GetWaypoints and follow up with the rest of your code for actually making the humanoid walk.

1 Like

I’m slightly new to coding myself, I was reading the wiki and got confused, in the :ComputeAsync wiki, it says once it is used, you can then use :GetWaypoints, so is this being used correctly?

path = game:GetService("PathfindingService"):CreatePath()
 path:ComputeAsync(rootpart.Position,head.Position)
points = path:GetWaypoints()

That should be correct, yes.

Holy moly it’s fixed, thanks a bunch man C:

1 Like

I have a pretty small question, but what did you do to fix this? Is the new updated method just keeping the humanoid from not breaking, or did my advice on print statements help you figure out what happened, or is it something else?

At first, I tried troubleshooting as you said, replacing the MoveTo() with error prints, however nothing was printing, therefore it has something to do with the for i,v in pairs loop.

I replaced the deprecated terms with the new ones, and instead of :MoveTo(v.Position) I did :MoveTo(points[i].Position)

You can take a look at the code here (Ignore the for loop that spawns in parts, that was also part of troubleshooting)

Code
local rootpart = script.Parent.HumanoidRootPart
local human = script.Parent.Humanoid

function findtarget ()
	local distance = 200
	local target = nil
	for i,v in pairs(workspace:GetChildren())do
		local humanoid = v:FindFirstChild("Humanoid")
		local head = v:FindFirstChild("Head")
		if humanoid and head and v.Name ~= ("dude5") then
			if (head.Position - rootpart.Position).magnitude < distance and humanoid.Health > 0 then
				distance = (head.Position - rootpart.Position).magnitude
				 target = head
			end
		end
	end
	return target
	
end
while wait() do
	local head = findtarget()
	
	if head then
		local ray = Ray.new(rootpart.Position, (head.Position-rootpart.Position).Unit *200)
		local hit,position = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})
		if hit then
			if hit:IsDescendantOf(head.Parent)then
				print("Error 1")
			else
				wait(.4)
				path = game:GetService("PathfindingService"):CreatePath() --FindPathAsync(rootpart.Position,head.Position)
				 path:ComputeAsync(rootpart.Position,head.Position)
				points = path:GetWaypoints()
				
				
				for i,v in pairs(points) do
      local p = Instance.new("Part",workspace)
      p.Anchored = true
      p.CanCollide = false
      p.CFrame = CFrame.new(v.Position)
      p.Size = Vector3.new(1,1,1)
		end	
				
				
				
				if path.Status == Enum.PathStatus.Success then
					
					
					
					for i,v in pairs(points) do
						print(v)
						human:MoveTo(points[i].Position)
						human.MoveToFinished:Wait()
						if v.Action == Enum.PathWaypointAction.Jump then
							wait()
							human.Jump = true
					
					
						end
						if (points[#points].Position - head.Position ).magnitude > 50 then
							break
						end
					
					end
				elseif path.Status ~= Enum.PathStatus.Success then
					print("cannot make it")
				end
			end
		end
	end
	
end

And that finally gave me this:

1 Like

Sorry to bug you again, but it seems that that was only a temporary fix :confused:

once the AI goes and follows 1 person (and kills them in my case, but separate script) , it just stands there and prints “Error 1”, any reason that u can see for that? q.q

New code
local rootpart = script.Parent.HumanoidRootPart
local human = script.Parent.Humanoid

function findtarget ()
	local distance = 60
	local target = nil
	for i,v in pairs(workspace:GetChildren())do
		local humanoid = v:FindFirstChild("Humanoid")
		local head = v:FindFirstChild("Head")
		if humanoid and head and v.Name ~= ("dude5") and v.Name ~= ("afk") then
			if (head.Position - rootpart.Position).magnitude < distance and humanoid.Health > 0 then
				distance = (head.Position - rootpart.Position).magnitude
				 target = head
			end
		end
	end
	return target
	
end
while wait() do
	local head = findtarget()
	
	if head then
		local ray = Ray.new(rootpart.Position, (head.Position-rootpart.Position).Unit *200)
		local hit,position = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})
		if hit then
			if hit:IsDescendantOf(head.Parent)then
				human:MoveTo(head.Position)
				print("Error 1")
			else
				wait(.4)
				path = game:GetService("PathfindingService"):CreatePath() --FindPathAsync(rootpart.Position,head.Position)
				 path:ComputeAsync(rootpart.Position,head.Position)
				points = path:GetWaypoints()
				
				
				for i,v in pairs(points) do
      local p = Instance.new("Part",workspace)
      p.Anchored = true
      p.CanCollide = false
      p.CFrame = CFrame.new(v.Position)
      p.Size = Vector3.new(1,1,1)
		end	
				
				
				
				if path.Status == Enum.PathStatus.Success then
					
					
					
					for i,v in pairs(points) do
						
						human:MoveTo(v.Position)
						human.MoveToFinished:Wait()
						if v.Action == Enum.PathWaypointAction.Jump then
							wait()
							human.Jump = true
					
					
						end
						if (points[#points].Position - head.Position ).magnitude > 50 then
							break
						end
					
					end
				elseif path.Status ~= Enum.PathStatus.Success then
					print("cannot make it")
				end
			end
		end
	end
	
end

Looks like you’re just moving it to itself with human:MoveTo(head.Position) whenever the part it hits is a descendant of the character.
Try removing that if statement and see if that works

without that if statement, he pauses every couple of steps for some reason, i’ve even gotten rid of the wait(.4)

I tested this script in a testing place of my own in studio, set up with dummies and walls, and I all I did was add a single line before print("Error 1"), which did not make the killer stand still:

if hit:IsDescendantOf(head.Parent) then
    human:MoveTo(head.Position)
    human.MoveToFinished:Wait()
    print("Error 1")
else

I also commented out the wait(0.4) on the literal next line after the else above, made the max seeking distance math.huge instead of 60, created a simple blacklist table so it would not keep looking for the same dummy, and added more print statements for making sure everything was working correctly.

This should not be exhibiting your behavior of just standing still though, it would just skip to the next victim on the list immediately. Does your murder script do anything with the humanoid’s movement before passing control back to the pathfinding script? It might be causing some weird interactions with MoveToFinished events or something…
The “pausing every couple of steps” part does not sound like it correlates with the pathfinding portion at all since these two sections of code are in separate sections of the same if statement.
The only way both portions of code would interact with each other is if the while wait() do loop did not wait between making the humanoid move and restarting the loop again, which would be fixed by my addition of the human.MoveToFinished:Wait() expression. The only other reason this pausing would be happening is from messing with the network ownership of the dummy since MoveTo commands to the humanoid would need to wait to be replicated back to the client.
This will not happen if you are testing it using Run mode instead of Play mode, or if you use rootpart:SetNetworkOwner() to set network ownership of the killer to the server

I have the exact script even with the addition of the movedtofinished in the place here

Once it kills the dummy, the following becomes staggered, it might just be my client in general or a slight lag but whatever it is, it just cannot catch me if i keep running, no matter how fast i make him.

I also have the model here if you want to take a look at it, I disabled most of the scripts, and the one with the pathfinding code in it is named “Follow”

I think I solved your problem, just place this statement after the first line:

local rootpart = script.Parent.HumanoidRootPart
rootpart:SetNetworkOwner() -- This statement
local human = script.Parent.Humanoid

It fixed it for the most part ^^ thanks!

1 Like