Trying to make Pathfinding AI

Hello, so i was trying to make a Pathfinding AI for my game, but my Bot is going pretty weird when Bot comes to player.

I’m sorry if you didn’t understood me, english is not my native language.

Here’s the video:

Here the Code:

---Services---
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Debris = game:GetService("Debris")
local PathfindingService = game:GetService("PathfindingService")

---Variables---
local Character = script.Parent
local Humanoid = Character.Humanoid
local RootPart = Character.HumanoidRootPart

local CanJump = true

local FieldOfView = 100
local AttackInterval = 0.5
local AttackRange = Vector3.new(5,10,7)
local CharacterSize = Character:GetExtentsSize()
local CurrentTarget = nil

local PathParams = {
	AgentRadius = (CharacterSize.Z / 2),
	AgentHeight = CharacterSize.Y,
	AgentCanJump = CanJump
}

---Functions---
local function GetNearestPlayer()
	local players = {}
	local nearest = math.huge
	local target = nil

	for _, player in pairs(Players:GetPlayers()) do
		local character = player.Character

		if character == nil then
			continue
		end

		local distance = (character.HumanoidRootPart.Position - RootPart.Position)
		if distance.Magnitude <= FieldOfView then
			table.insert(players, {
				Magnitude = distance.Magnitude,
				Player = player
			})
		end
	end

	for _, entry in pairs(players) do
		local Magnitude = entry.Magnitude
		local player = entry.Player

		if Magnitude < nearest then
			nearest = Magnitude
			target = player
		end
	end

	return target
end

---Connections---
RunService.Heartbeat:Connect(function()
	local player = GetNearestPlayer()

	if player == nil then
		return
	end

	local player_character = player.Character

	if player_character == nil then
		return
	end

	local character_humanoid = player_character.Humanoid

	if character_humanoid.Health <= 0 then
		return
	end

	local target_RootPart = player_character.HumanoidRootPart

	local beginning = RootPart.Position
	local destination = target_RootPart.Position

	local path = PathfindingService:CreatePath(PathParams)
	local secPath = PathfindingService:CreatePath(PathParams)

	path:ComputeAsync(beginning, destination)
	secPath:ComputeAsync(beginning, workspace.Lolo.Position)

	CurrentTarget = player

	if path.Status == Enum.PathStatus.Success then
		local waypoints = path:GetWaypoints()

		for _, waypoint in pairs(waypoints) do
			if player or player_character or character_humanoid.Health > 0 then

				if waypoint.Action == Enum.PathWaypointAction.Jump then
					Humanoid.Jump = true
				end

				Humanoid:MoveTo(waypoint.Position)
				Humanoid.MoveToFinished:Wait()
			else
				return
			end;
		end
	end

	if secPath.Status == Enum.PathStatus.Success then
		for _, waypoint in pairs(secPath:GetWaypoints()) do
			if not player or not player_character or character_humanoid.Health <= 0 then
				if waypoint.Action == Enum.PathWaypointAction.Jump then
					Humanoid.Jump = true
				end

				Humanoid:MoveTo(waypoint.Position)
				Humanoid.MoveToFinished:Wait()
			else
				return
			end
		end
	end

end)

---Initializations---
RootPart:SetNetworkOwner(nil)

while wait(AttackInterval) do
	if CurrentTarget == nil then
		continue
	end

	local target_character = CurrentTarget.Character or CurrentTarget.CharacterAdded:Wait()
	local range = (AttackRange.X + AttackRange.Y + AttackRange.Z) / 3

	if (target_character.HumanoidRootPart.Position - RootPart.Position).Magnitude < range then
		continue
	end

	local origin =(RootPart.CFrame * CFrame.new(0,0,-2)).Position
	local region = Region3.new(origin - AttackRange, origin + AttackRange)

	local parts = workspace:FindPartsInRegion3WithIgnoreList(region, Character:GetDescendants())
	for _, part in pairs(parts) do
		local character = part:FindFirstAncestor(target_character.Name)

		if character == nil then
			continue
		end

		local humanoid = character.Humanoid

		if humanoid:FindFirstChild("Debounce") then
			continue
		end

		local deb = Instance.new("BoolValue")
		deb.Name = "Debounce"
		deb.Value = true
		deb.Parent = humanoid

		Debris:AddItem(deb, AttackInterval)
		humanoid.Health = 0
	end
end
2 Likes

I believe you are computing and create a new path too fast

1 Like

Try making a new path only when either current path is complete or when characters position is greater than 15 studs away from the last waypoint

1 Like

Well, i tried to realise that, but it still won’t work

RunService.Heartbeat:Connect(function()
	local player = GetNearestPlayer()

	if player == nil then
		return
	end

	local player_character = player.Character

	if player_character == nil then
		return
	end

	local character_humanoid = player_character.Humanoid

	if character_humanoid.Health <= 0 then
		return
	end

	local target_RootPart = player_character.HumanoidRootPart

	local beginning = RootPart.Position
	local destination = target_RootPart.Position
	
	local secPath = nil;
	local path = PathfindingService:CreatePath(PathParams)

	path:ComputeAsync(beginning, destination)

	CurrentTarget = player

	if path.Status == Enum.PathStatus.Success then
		local waypoints = path:GetWaypoints()

		for _, waypoint in pairs(waypoints) do
			if player or player_character or character_humanoid.Health > 0 then

				if waypoint.Action == Enum.PathWaypointAction.Jump then
					Humanoid.Jump = true
				end

				Humanoid:MoveTo(waypoint.Position)
				Humanoid.MoveToFinished:Wait()
			else
				secPath = PathfindingService:CreatePath(PathParams)
				secPath:ComputeAsync(beginning, workspace.Lolo.Position)
			end;
		end
	end
	
	if secPath and secPath.Status == Enum.PathStatus.Success then
		for _, waypoint in pairs(secPath:GetWaypoints()) do
			if not player or not player_character or character_humanoid.Health <= 0 then
				if waypoint.Action == Enum.PathWaypointAction.Jump then
					Humanoid.Jump = true
				end

				Humanoid:MoveTo(waypoint.Position)
				Humanoid.MoveToFinished:Wait()
			else
				break
			end
		end
	end
end)
1 Like

Try something like this, using pathfinding inside of a “HeartBeat” event will cause problems

local target = nil 

local PathfindingService = game:GetService('PathfindingService')

local PathParams = {
	AgentRadius = (CharacterSize.Z / 2),
	AgentHeight = CharacterSize.Y,
	AgentCanJump = CanJump
}
 


local function startAI()
	
	repeat wait(.2) 
	until target ~= nil 

	local path = PathfindingService:CreatePath(PathParams)


	local CurrentTarget = target

	local beginning = RootPart.Position
	local destination = CurrentTarget.Position
	
	path:ComputeAsync(beginning, destination)

	if path.Status == Enum.PathStatus.Success then
		local waypoints = path:GetWaypoints()

		for _, waypoint in pairs(waypoints) do
			if target ~= CurrentTarget then
				break
			end
			
			if (CurrentTarget.Position-waypoints[#waypoints].Position).Magnitude > 15 then
				break
			end
			
			if Humanoid.Health <= 0 then
				break
			end
			 
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				Humanoid.Jump = true
			end

			Humanoid:MoveTo(waypoint.Position)
			Humanoid.MoveToFinished:Wait()
			
		end
	else
		wait()
		target = nil 
	end
	
	if Humanoid.Health > 0 then
		startAI()
	end
end

spawn(function() 
	startAI()
end)

game:GetService('RunService').Heartbeat:Connect(function()
	
	target =  GetNearestPlayer()
end)
4 Likes

It actually worked, but it got slower, i’ll try to do something with HeartBeat function, but this method is good

change the “repeat wait(.2)” to “repeat wait()”