Make Pathfinding Bot Smarter

Hello Developers,
I have a script which makes Bot follows the path but if Bot finds the target,
it chases the target. But my Bot is not usually able to detect some walls, and be stuck.
How can I make Bot smarter?

-- Scripted by FunnyDevGames
local MaxDistance = 100 -- Maximum distance Bot can find.

local CanWander = false -- If this is true, Bot will move to a random position based on WanderX and WanderZ when it doesn't find the target.
local WanderX, WanderZ = 10, 10

local CanMoveToPath = true -- If this is true, Bot will move along the set path when it doesn't find the target.
local Paths = workspace.Paths -- The parent folder of the paths that Bot will move to when CanMoveToPath is true.
-- Insert one or more BaseParts within the folder.

-- Do not use CanWander and CanMoveToPath at the same time.
-- It can move incorrectly.

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local Bot = script.Parent
local Humanoid = Bot.Humanoid
local HumanoidRootPart = Bot.HumanoidRootPart
local Chasing = false
local CanSoundPlay = true
local CanMove = true
local IsRunning = false
local StartTime = 0

local Path
local Waypoints

do
	local function Raycast(PlayerCharacter, PlayerRootPart, Distance)
		local NewRaycastParams = RaycastParams.new()
		local FilterDescendantsInstances = {}
		NewRaycastParams.FilterType = Enum.RaycastFilterType.Exclude
		for _, Object in ipairs(Bot:GetDescendants()) do
			if Object:IsA("BasePart") then
				table.insert(FilterDescendantsInstances, Object)
			end
		end
		for _, Object in ipairs(PlayerCharacter:GetDescendants()) do
			if Object:IsA("BasePart") then
				table.insert(FilterDescendantsInstances, Object)
			end
		end
		NewRaycastParams.FilterDescendantsInstances = FilterDescendantsInstances
		local RayDirection = PlayerRootPart.Position - HumanoidRootPart.Position
		local RaycastResult = workspace:Raycast(HumanoidRootPart.Position, RayDirection, NewRaycastParams)
		return if RaycastResult and Distance > 15 then true else false
	end
	
	local function CheckCondition(Player, PlayerCharacter, PlayerRootPart, AllDistance, Distance)
		if (Distance <= MaxDistance) and not Raycast(PlayerCharacter, PlayerRootPart, Distance) then
			AllDistance[Distance] = Player
		end
	end
	
	local function GetNearestPlayer()
		local AllDistance = {}
		local Numbers = {}
		Bot = script.Parent
		Humanoid = Bot.Humanoid
		HumanoidRootPart = Bot.HumanoidRootPart
		for _, Player in ipairs(Players:GetPlayers()) do
			local PlayerCharacter = Player.Character
			if PlayerCharacter:FindFirstChild("Humanoid").Health > 0 and PlayerCharacter:FindFirstChild("Enemy") == nil and PlayerCharacter:FindFirstChild("ForceField") == nil then
				local PlayerRootPart = PlayerCharacter:FindFirstChild("HumanoidRootPart")
				local Distance = (HumanoidRootPart.Position - PlayerRootPart.Position).Magnitude
				if CanSoundPlay then
					CheckCondition(Player, PlayerCharacter, PlayerRootPart, AllDistance, Distance)
				else
					if tick() - StartTime >= 10 then
						CheckCondition(Player, PlayerCharacter, PlayerRootPart, AllDistance, Distance)
					else
						AllDistance[Distance] = Player
					end
				end
			end
		end
		for Distance in pairs(AllDistance) do
			Numbers[#Numbers + 1] = Distance
		end
		if #Numbers == 0 then
			return
		end
		local SmallestNumber = math.min(table.unpack(Numbers))
		return AllDistance[SmallestNumber]
	end
	
	local function NotChasing()
		IsRunning = true
		if not (CanWander and CanMoveToPath) then
			if CanWander then
				while true do
					task.wait()
					if Chasing == false and Bot:FindFirstChild("Killing").Value == false then
						local DestinationX, DestinationZ = HumanoidRootPart.Position.X + math.random(-WanderX, WanderX), HumanoidRootPart.Position.Z + math.random(-WanderZ, WanderZ)
						Humanoid:MoveTo(Vector3.new(DestinationX, 0, DestinationZ))
						task.wait(math.random(4, 6))
					end
				end
			elseif CanMoveToPath then
				local AllPaths = Paths:GetChildren()
				if not (#AllPaths == 0) then
					while true do
						task.wait()
						if Chasing == false and Bot:FindFirstChild("Killing").Value == false then
							CanSoundPlay = true
							StartTime = tick()
							for _, AnimationTrack in ipairs(Humanoid:GetPlayingAnimationTracks()) do
								AnimationTrack:Stop()
							end							
							HumanoidRootPart.Ambience:Stop()
							local RandomPath = AllPaths[math.random(1, #AllPaths)]
							local TemporaryPath = PathfindingService:CreatePath({
								AgentRadius = 2,
								AgentHeight = 1.25,
								AgentCanJump = true,
								WaypointSpacing = 3,
								Costs = {
									Water = 25
								}
							})
							TemporaryPath:ComputeAsync(HumanoidRootPart.Position, RandomPath.Position)
							local TemporaryWaypoints = TemporaryPath:GetWaypoints()
							for i = 1, #TemporaryWaypoints do
								if not (i == #TemporaryWaypoints) then
									local c = game.ServerStorage.Waypoint:Clone()
									c.Position = TemporaryWaypoints[i].Position
									c.Parent = workspace.Waypoints
								else
									local c = game.ServerStorage.LastWaypoint:Clone()
									c.Position = TemporaryWaypoints[i].Position
									c.Parent = workspace.Waypoints
								end
							end
							if TemporaryPath and TemporaryWaypoints and TemporaryPath.Status == Enum.PathStatus.Success then
								local RunAnimation = Humanoid.Animator:LoadAnimation(script.Parent.Animate:FindFirstChild("RunAnim", true))
								RunAnimation:Play()
								RunAnimation:AdjustSpeed(3)
								for Index = 1, #TemporaryWaypoints do
									Humanoid:MoveTo(TemporaryWaypoints[Index].Position)
									if TemporaryWaypoints[Index].Action == Enum.PathWaypointAction.Jump then
										task.wait(0.25)
										Humanoid.Jump = true
									end
									Humanoid.MoveToFinished:Wait()
								end
								workspace.Waypoints:ClearAllChildren()
								RunAnimation:Stop()
								script.Parent.Animate.Enabled = true
							end
						end
					end
				else
					error("No path exists!")
				end
			end
		else
			error("Cannot use both function!")
		end
	end
	
	while true do
		task.wait()
		pcall(function()
			local NearestPlayer = GetNearestPlayer()
			if NearestPlayer and CanMove then
				if CanSoundPlay then
					CanSoundPlay = false
					HumanoidRootPart.Spotted:Play()
					HumanoidRootPart.Ambience:Play()
					StartTime = tick()
				end
				Chasing = true
				CanMove = false
				script.Parent.Animate.Enabled = true
				Path = PathfindingService:CreatePath({
					AgentRadius = 2,
					AgentHeight = 1.25,
					AgentCanJump = true,
					WaypointSpacing = 3,
					Costs = {
						Water = 25
					}
				})
				Path:ComputeAsync(HumanoidRootPart.Position, NearestPlayer.Character:FindFirstChild("HumanoidRootPart").Position)
				Waypoints = Path:GetWaypoints()
				for i = 1, #Waypoints do
					if not (i == #Waypoints) then
						local c = game.ServerStorage.Waypoint:Clone()
						c.Position = Waypoints[i].Position
						c.Parent = workspace.Waypoints
						task.spawn(function()
							task.wait(0.1)
							c:Destroy()
						end)
					else
						local c = game.ServerStorage.LastWaypoint:Clone()
						c.Position = Waypoints[i].Position
						c.Parent = workspace.Waypoints
						task.spawn(function()
							task.wait(0.1)
							c:Destroy()
						end)
					end
				end
				if Path and Waypoints and Path.Status == Enum.PathStatus.Success then
					Humanoid:MoveTo(Waypoints[3].Position)
					if Waypoints[3].Action == Enum.PathWaypointAction.Jump then
						task.spawn(function()
							task.wait(0.25)
							Humanoid.Jump = true
						end)
					end
				elseif Path.Status == Enum.PathStatus.NoPath then
					Humanoid:MoveTo(NearestPlayer.Character.PrimaryPart.Position)
				end
			elseif not NearestPlayer then
				Chasing = false
				if CanWander or CanMoveToPath then
					Path = nil
					Waypoints = nil
					if CanMoveToPath then
						script.Parent.Animate.Enabled = false
					end
					if not IsRunning then
						task.spawn(NotChasing)
					end
					Humanoid.MoveToFinished:Wait()
				end
			end
			CanMove = true
		end)
	end
end

Any responses and feedback be appreciated!

1 Like