How to detect characters in pathfinding?

Hi. I’m making a game, in this game there are two teams, blue and red. I coded a script that uses pathfinding to walk enemies. But there is a problem. Pathfinding that ignores unanchored objects, so it also ignores characters. This is why my soldiers ignore their teammates. So when they are going to attack the enemy, they intertwine to attack the enemy. How can I detect a teammate and have him create a path between the enemy?

1 Like

oof sorry guys i forgot to post my code. here is:

local soldier = script.Parent
local basePart = soldier.Torso
local humanoid = soldier.Humanoid
local damageDelay = 1
local pathfindingservice = game:GetService("PathfindingService")
local runservice = game:GetService("RunService")
soldier.PrimaryPart:SetNetworkOwner(nil)



local function createPath(destination)
	local pathfindingservice = game:GetService("PathfindingService")
	local pathParameters = {
		AgentHeight = 5.162,
		AgentRadius = 2,
		AgentCanJump = false


	}
	local path = pathfindingservice:CreatePath(pathParameters)
	path:ComputeAsync(basePart.Position, destination.Torso.Position)

	for i, w in pairs(workspace.waypoints:GetChildren()) do
		w:Destroy()
	end
	local waypoints = path:GetWaypoints()
	for i, w in pairs(waypoints) do
		local waypoint = Instance.new("Part")
		waypoint.Name = tostring(table.find(waypoints,w))
		waypoint.Position = w.Position
		waypoint.CanCollide = false
		waypoint.Parent = workspace.waypoints
		waypoint.Shape = "Ball"
		waypoint.Size = Vector3.new(1, 1, 1)
		waypoint.Anchored = true
	end

	return path
end
local blockedTargets = {}
local target 



local function findTarget(blockedTargets)
	local targets = workspace.BlueTeamSoldiers:GetChildren()

	if #targets ~= 0 then
		local maxDistance = math.huge
		local nearestTarget
		if targets then

			for i, t in pairs(targets) do
				if t.Humanoid.Health > 0 then
					if not table.find(blockedTargets,t) then
						if t.Torso then
							local distance = (basePart.Position - t.Torso.Position).Magnitude
							if distance < maxDistance then
								nearestTarget = t
								maxDistance = distance
							end	
						end
					else	
						local pathfindingservice = game:GetService("PathfindingService")
						local pathParameters = {
							AgentHeight = 5.162,
							AgentRadius = 2,
							AgentCanJump = false


						}
						local path = pathfindingservice:CreatePath(pathParameters)
						path:ComputeAsync(basePart.Position, t.Torso.Position)
						if path.Status == Enum.PathStatus.Success then
							table.remove(blockedTargets,table.find(blockedTargets,t))

						end
					end
				else
					t.Parent = workspace.DiedSoldiers
				end

			end
		else	
			nearestTarget = nil
		end
		return nearestTarget
	end
end
local result = {}
local damaged = Instance.new("BoolValue")
damaged.Value = false
damaged:GetPropertyChangedSignal("Value"):Connect(function()
	if damaged.Value == true then
		wait(damageDelay)
		damaged.Value = false
	end	
end)

function rotateTowards(target, this)
	local targetPosition = target.Position
	local thisPosition = this.Position

	local rotationTowards = CFrame.new(thisPosition, targetPosition)

	this.CFrame = this.CFrame:Lerp(rotationTowards, 0.5)
end

local function walkTo(destination)
	local path = nil
	local waypoints = nil
	while true do
		target = findTarget(blockedTargets)
		if destination ~= target then
			break
		end
		local distance = (basePart.Position - destination.Torso.Position).Magnitude

		if destination.Humanoid.Health > 0 then
			path = createPath(destination)
			waypoints = path:GetWaypoints() 
			if waypoints[2] and distance > 4 then

				humanoid:MoveTo(waypoints[2].Position)

			end
			if distance < 4 and damaged.Value == false then
				rotateTowards(destination.Torso,basePart)
				local anim = humanoid:LoadAnimation(script.SwordAnim)
				anim:Play()
			end
			soldier.SwordHandle.Touched:Connect(function(hit)
				if hit.Parent == destination  and damaged.Value == false then
					destination.Humanoid.Health -= 10
					damaged.Value = true
				end

			end)

		else
			break
		end
		if path.Status == Enum.PathStatus.NoPath then
			table.insert(blockedTargets,destination)
			return blockedTargets
		else
			for i, t in pairs(blockedTargets) do
				if t == destination then
					table.remove(blockedTargets,table.find(blockedTargets,t))
					if path.Status == Enum.PathStatus.NoPath then
						break
					end
				end
			end

		end
	end
	return blockedTargets

end

local function patrol()
	local targetList = workspace.RedTeamSoldiers:GetChildren()
	if #targetList > 0 then
		target = findTarget(result)

		if target then
			result = walkTo(target)

		end
	else

	end
	wait(0.00001)
end

while true do
	patrol()
end


1 Like

To make your soldiers detect their teammates and avoid intertwining, you need to modify your pathfinding algorithm to take into account the positions of both enemies and allies.

One way to do this is to modify your findTarget function to exclude targets that are too close to the soldier’s allies. You can do this by iterating over the list of targets and calculating the distance between each target and all nearby allies. If a target is too close to any ally, it should be excluded from the list of potential targets.

Here’s an example implementation:

local function findTarget(blockedTargets)
	local targets = workspace.BlueTeamSoldiers:GetChildren()
	local allies = workspace.BlueTeamSoldiers:GetChildren()

	if #targets ~= 0 then
		local maxDistance = math.huge
		local nearestTarget
		if targets then

			for i, t in pairs(targets) do
				if t.Humanoid.Health > 0 then
					local tooClose = false
					for j, a in pairs(allies) do
						if a ~= soldier and a.Humanoid.Health > 0 then
							local distance = (a.Torso.Position - t.Torso.Position).Magnitude
							if distance < 10 then
								tooClose = true
								break
							end
						end
					end
					if not tooClose and not table.find(blockedTargets,t) then
						if t.Torso then
							local distance = (basePart.Position - t.Torso.Position).Magnitude
							if distance < maxDistance then
								nearestTarget = t
								maxDistance = distance
							end	
						end
					else	
						local pathfindingservice = game:GetService("PathfindingService")
						local pathParameters = {
							AgentHeight = 5.162,
							AgentRadius = 2,
							AgentCanJump = false


						}
						local path = pathfindingservice:CreatePath(pathParameters)
						path:ComputeAsync(basePart.Position, t.Torso.Position)
						if path.Status == Enum.PathStatus.Success then
							table.remove(blockedTargets,table.find(blockedTargets,t))

						end
					end
				else
					t.Parent = workspace.DiedSoldiers
				end

			end
		else	
			nearestTarget = nil
		end
		return nearestTarget
	end
end

This implementation checks if a target is too close to any ally, and excludes it from the list of potential targets if it is. You can adjust the threshold distance (10 in this example) to suit your needs.

With this modification, your soldiers should be able to navigate around their allies and avoid intertwining.

No, i dont meant that. I just want to create a path between enemy and detect teammate as obstacle. but pathfinding ignores unanchored objects like characters and i dont know how to detect unanchored objects like characters.

therefore, when the soldier does not detect his teammates, he walks on the enemies and when the teammate gets in his way, he hits his teammates.

1 Like

I see, thank you for clarifying. In that case, you can modify your pathfinding algorithm to take into account both anchored and unanchored objects.

To detect unanchored objects like characters, you can use a Raycast or a Region3 object to check if there are any obstacles in the path of your soldier. Here’s an example implementation:

local function isObstacleInPath(startPos, endPos, obstacle)
 local direction = (endPos - startPos).Unit
 local distance = (endPos - startPos).Magnitude
 local ray = Ray.new(startPos, direction * distance) 
local hitPart, hitPos = workspace:FindPartOnRayWithIgnoreList(ray, {obstacle})
if hitPart then
	return true
else
	return false
end

end

This function takes in the start and end positions of your soldier’s path, as well as the obstacle to check for. It returns true if there is an obstacle in the path, and false otherwise.

You can then modify your pathfinding algorithm to use this function to check for obstacles in the soldier’s path. Here’s an example implementation:

local function findPath(startPos, endPos, obstacles) 
local pathfindingService = game:GetService("PathfindingService") 
local path = pathfindingService:CreatePath({ AgentHeight = 5.162, AgentRadius = 2, AgentCanJump = false }) path:ComputeAsync(startPos, endPos)

if path.Status == Enum.PathStatus.Success then
	local waypoints = path:GetWaypoints()
	local pathBlocked = false
	for i = 1, #waypoints - 1 do
		local startPos = waypoints[i].Position
		local endPos = waypoints[i + 1].Position
		for j, obstacle in ipairs(obstacles) do
			if isObstacleInPath(startPos, endPos, obstacle) then
				pathBlocked = true
				break
			end
		end
		if pathBlocked then
			break
		end
	end
	if not pathBlocked then
		return waypoints
	end
end

return nil

end

This implementation checks for obstacles in the soldier’s path by iterating over each segment of the path and checking for obstacles using the isObstacleInPath function. If an obstacle is found, the path is marked as blocked and the function returns nil.

With this modification, your soldier should be able to detect both anchored and unanchored objects like characters and navigate around them to reach the enemy target without hitting their teammates.

let me know if this answer was helpful!

1 Like