A few questions about pathfinding

Dont really know how to use pathfinding efficiently so im coming here to find out how i can do stuff better and fix some bugs

  1. How do i visualize paths better?, as currently im just creating a part per waypoint, which isnt the best as shown here

  1. What do i do about it jumping?, didnt know how to make it jump correctly and tried following some solution that other players had and uh

  1. What happens if i call a MoveTo if theres already one active? Basically what if i wanted the bot to wander around if no players are withing a certain distance, and during the wander it spots a player? (Already got the players distance and stuff).

  2. What can i do to combat the jittering / lagging behind as shown

  1. how come the {Costs} do not work?, i have it set up, but the nextbot just decides instead of avoiding the wall it should avoid, it goes straight through it.

Heres the code

local Players = game.Players
local DisableAllBots = false
local Debug = true

local PathFindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")

local function FindNearest(NBC)
	local NearestPlayer
	local NearestDistance
	
	for _, Player in (Players:GetPlayers()) do
		if Player.Character and Player.Character.Humanoid and Player.Character.Humanoid.Health ~= 0 then
			local Mag = (Player.Character.HumanoidRootPart.Position - NBC.Position).Magnitude
			
			if Player.Character.IsInSafeZone == false then
				if NearestDistance then
					if Mag < NearestDistance then NearestDistance = Mag; NearestPlayer = Player.Character end
				else
					NearestDistance = Mag; NearestPlayer = Player.Character
				end				
			end
		end
	end
	
	return NearestPlayer, NearestDistance
end

local function pfm(NextBot)
	local Path = PathFindingService:CreatePath({
		
		['AgentRadius'] = 5,
		['AgentHeight'] = 5,
		['AgentCanJump'] = true,
		['WaypointSpacing'] = 3,
		
		Costs = {
			Water = 20,
			SmoothPlastic = 1,
			ForceField = math.huge,
			Untouchable = math.huge
		}	
	})
	local Waypoints
	local NextWaypointIndex
	local reachedConnection
	local blockedConnection
	
	local NearestPlr, NearestDistance = FindNearest(NextBot.Character)
	
	if not NearestPlr or NearestDistance > NextBot.ChangeableValues.DetectionDistance.Value then
		return "No Near Players"
	else
		local Yes, No = pcall(function()
			Path = PathFindingService:FindPathAsync(NextBot.PrimaryPart.Position, NearestPlr.HumanoidRootPart.Position)
		end)


		if Yes and Path.Status == Enum.PathStatus.Success then
			Waypoints = Path:GetWaypoints()

			blockedConnection = Path.Blocked:Connect(function(BwI)
				if BwI >= NextWaypointIndex then
					blockedConnection:Disconnect()
					pfm(NextBot)
				end
			end)


			for	i, v in ipairs(Waypoints) do

				if v.Action == Enum.PathWaypointAction.Jump then
					NextBot.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
				end

				local Part = Instance.new("Part", workspace.Extras)
				Part.Shape = Enum.PartType.Ball
				Part.Size = Vector3.new(1,1,1)
				Part.Anchored = true
				Part.Position = v.Position
				Part.Material = Enum.Material.Neon
				Part.Color = Color3.new(0,4,0)
				Part.CanCollide = false
				Part.Transparency = 0.5

				NextBot.Humanoid:MoveTo(v.Position)
				NextBot.Humanoid.MoveToFinished:Wait()

			end		
		else
			warn("Failed To Compute A Valid Path, Did you make sure that the NextBot Isnt Trapped / Stuck?: " .. if No then No else "Nil")
		end
	end
end

local function PathFindingMovement(NextBot)
	local Run
	
	Run = RunService.Heartbeat:Connect(function(DT)
		if NextBot.Humanoid.Active.Value == true and DisableAllBots == false then
			local D = pfm(NextBot)
			
			if D and Debug == true then
				print(D)
			end			
		else
			Run:Disconnect()
		end
	end)
end
Unedited Code
-- The NextBot Handler Module --
local Players = game.Players
local DisableAllBots = false
local Debug = true

local PathFindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")

-- Functions
local function FindNearest(NBC)
	local NearestPlayer
	local NearestDistance
	
	for _, Player in (Players:GetPlayers()) do
		if Player.Character and Player.Character.Humanoid and Player.Character.Humanoid.Health ~= 0 then
			local Mag = (Player.Character.HumanoidRootPart.Position - NBC.Position).Magnitude
			
			if Player.Character.IsInSafeZone == false then
				if NearestDistance then
					if Mag < NearestDistance then NearestDistance = Mag; NearestPlayer = Player.Character end
				else
					NearestDistance = Mag; NearestPlayer = Player.Character
				end				
			end
		end
	end
	
	return NearestPlayer, NearestDistance
end

local function MoveToMovement(NextBot, ValFol)
	local Stepped
	local NearestPlayer, NearestDistance
	
	Stepped = RunService.Heartbeat:Connect(function(DTime)
		if NextBot.Humanoid.Active.Value == true then
			NearestPlayer, NearestDistance = FindNearest(NextBot.Character)

			if NearestPlayer and NearestDistance then
				if NearestDistance <= ValFol.DetectionDistance.Value then
					NextBot.Humanoid:MoveTo(NearestPlayer.HumanoidRootPart.Position)
				end
			end
		else
			Stepped:Disconnect()
		end
	end)
end

local function pfm(NextBot)
	local Path = PathFindingService:CreatePath({
		
		['AgentRadius'] = 5,
		['AgentHeight'] = 5,
		['AgentCanJump'] = true,
		['WaypointSpacing'] = 3,
		
		Costs = {
			Water = 20,
			SmoothPlastic = 1,
			ForceField = math.huge,
			Untouchable = math.huge
		}	
	})
	local Waypoints
	local NextWaypointIndex
	local reachedConnection
	local blockedConnection
	
	local NearestPlr, NearestDistance = FindNearest(NextBot.Character)
	
	if not NearestPlr or NearestDistance > NextBot.ChangeableValues.DetectionDistance.Value then
		return "No Near Players"
	else
		local Yes, No = pcall(function()
			Path = PathFindingService:FindPathAsync(NextBot.PrimaryPart.Position, NearestPlr.HumanoidRootPart.Position)
		end)


		if Yes and Path.Status == Enum.PathStatus.Success then
			Waypoints = Path:GetWaypoints()

			blockedConnection = Path.Blocked:Connect(function(BwI)
				if BwI >= NextWaypointIndex then
					blockedConnection:Disconnect()
					pfm(NextBot)
				end
			end)


			for	i, v in ipairs(Waypoints) do

				if v.Action == Enum.PathWaypointAction.Jump then
					NextBot.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
				end

				local Part = Instance.new("Part", workspace.Extras)
				Part.Shape = Enum.PartType.Ball
				Part.Size = Vector3.new(1,1,1)
				Part.Anchored = true
				Part.Position = v.Position
				Part.Material = Enum.Material.Neon
				Part.Color = Color3.new(0,4,0)
				Part.CanCollide = false
				Part.Transparency = 0.5

				NextBot.Humanoid:MoveTo(v.Position)
				NextBot.Humanoid.MoveToFinished:Wait()

			end		
		else
			warn("Failed To Compute A Valid Path, Did you make sure that the NextBot Isnt Trapped / Stuck?: " .. if No then No else "Nil")
		end
	end
end

local function PathFindingMovement(NextBot)
	local Run
	
	Run = RunService.Heartbeat:Connect(function(DT)
		if NextBot.Humanoid.Active.Value == true and DisableAllBots == false then
			local D = pfm(NextBot)
			
			if D and Debug == true then
				print(D)
			end			
		else
			Run:Disconnect()
		end
	end)
end

-- Module
local Nbot = {}

Nbot.Setup = function(NextBot)
	NextBot.PrimaryPart:SetNetworkOwner(nil)
	local ValFol = NextBot.ChangeableValues

	local NextBotSpeed = ValFol.Speed.Value
	local NextBotJumpPower = ValFol.JumpPower.Value
	local NextBotHealth = ValFol.Health.Value
	local CanBeKilled = ValFol.CanBeKilled.Value
	local Pic = ValFol.Image.Value
	
	local NBotHumanoid = NextBot.Humanoid
	
	NBotHumanoid.WalkSpeed = NextBotSpeed
	NBotHumanoid.JumpPower = NextBotJumpPower
	
	if CanBeKilled == true then
		NBotHumanoid.MaxHealth = NextBotHealth; NBotHumanoid.Health = NextBotHealth
	else
		local ff = Instance.new("ForceField", NextBot)
		ff.Visible = false
		NBotHumanoid.MaxHealth = math.huge; NBotHumanoid.Health = math.huge
	end
	
	NextBot.Character.Front.ImageLabel.Image = "rbxassetid://" .. Pic
	NextBot.Character.Back.ImageLabel.Image = "rbxassetid://" .. Pic
	
	if not NextBot.Humanoid:GetAttribute("Active") then
		NextBot.Humanoid:SetAttribute("Active", false)
	end
	
	return "Setup Complete"
end

Nbot.Start = function(NextBot)
	local ValFol = NextBot.ChangeableValues
	NextBot.Humanoid.Active.Value = true

	if ValFol.SmartAi.Value == true then
		PathFindingMovement(NextBot)
		print("Smart Movement Activated")
	else
		MoveToMovement(NextBot, ValFol)
		print("Basic Movement Activated")
	end	
	
end

Nbot.Stop = function(NextBot)
	NextBot.Humanoid.Active.Value = false
end

Nbot.DisableAllBots = function(A)
	if A then
		print("This function doesnt require anything to be sent, disables all bots")
	end
	
	if DisableAllBots == true then
		print("Bots are already disabled")
		return "Failed, Bots Are Disabled Already"
	end
	DisableAllBots = true
	return "Bots Disabled"
end

Nbot.EnableAllBots = function(A)
	if A then
		print("This function doesnt require anything to be sent, enables all bots")
	end

	if DisableAllBots == false then
		print("Bots are already enabled")
		return "Failed, Bots Are Enabled Already"
	end
	DisableAllBots = false
	return "Bots Enabled"
end

return Nbot

Using Heartbeat loop is not a good idea.

image

Like in the screenshot above, you can see the AI making a ridiculous amount of waypoints that seemingly stretch out. This happens because you’re using Heartbeat which runs every frame. Instead of yielding until the current path is finished, it’s calculating waypoints every single frame, and Pathfinding is not a light process.

This leads to weird jittery movement, and broken pathfinding.

You should use while true do instead.

1 Like

@Downrest So basically mate I think keep doing what you doing! It’s good

For this, do i just change it to white true do? or is there some stuff i gotta setup before i use while true do
(game immediately lagged out when it started running)

1 Like

You could either do:

while task.wait() do
	-- CODE HERE
end

or

while true do
	-- CODE HERE
	task.wait()
end

Don’t do this:

while true do
	-- CODE HERE
end

It will lead to script exhaustion because it’s running the code incredibly fast (without any kind of pauses).

Alright, used task.wait and it doesnt spam the circles anymore so thats good

so i was wondering how i would get it to jump high?, if i can

its jumppower is at 300, so it should have no problem reaching players, but it just detects that theres no path even though i have it so it can jump

If you want to make a fast loop without script exhaustion, use RunService

the path its not in a permanent y, it detects in air i think

thats why he can do parkour, why 300 of jump pover???