Problems with AI targeting each other

I am currently working on a small project for fun, and I’ve been watching a lot of videos trying to figure it out. However, I’ve come across an issue I can’t seem to fix, it’s very small but super annoying.

In this game I have two factions of npcs. The “Hungry Bandits” and “Dust Bandits”. They are supposed to be hostile towards the player and towards each other but ignore their own members. I have their controller script set up so that they are hostile towards players, and they attack each other if I spawn them directly into the workspace. However, if I spawn them through a spawn block, they remain hostile to players but start to ignore each other! Can anyone help me figure out why?

this is the controller script I have set up:

local hum = script.Parent:WaitForChild("Humanoid")
local root = script.Parent:WaitForChild("HumanoidRootPart")
local spawnPos = script.Parent:WaitForChild("SpawnPosition")
local thisFaction = hum:WaitForChild("Faction")

local visionRange = 30
local attackRange = script.AttackRange.Value
local abandonRange = 50
local abandonRangeFromHome = 200

local target = nil

while wait() do
	if target then 
		target.Humanoid.HealthChanged:Connect(function(newHealth)
			if newHealth <= 0 then
				target = nil
				hum:MoveTo(spawnPos.Value)
			end
		end)
		
		--calculate distance and attack player
		local plrRoot = target.HumanoidRootPart
		local distance = (root.Position - plrRoot.Position).magnitude
		local distanceFromHome = (spawnPos.Value - plrRoot.Position).magnitude
		
		hum:MoveTo(plrRoot.Position - CFrame.new(root.Position, plrRoot.Position).LookVector * attackRange)
		
		if distance <= attackRange + 2 then
			script.AttackRemote:Fire(plrRoot)
		end
		
		if distance > abandonRange then
			target = nil
			hum:MoveTo(spawnPos.Value)
		end
		
		if distanceFromHome > abandonRangeFromHome then
			target = nil
			hum:MoveTo(spawnPos.Value)
		end
		
	else
	--see if any players are in range
	for i, v in pairs(game.Workspace:GetChildren()) do
			
		if not game.Workspace:FindFirstChild(v.Name) then continue end
			local char = game.Workspace[v.Name]
			local me = script.Parent
			if char:FindFirstChild("HumanoidRootPart") and char ~= me then
				local plrRoot = char:FindFirstChild("HumanoidRootPart")
				local hum = char:FindFirstChild("Humanoid")
				local faction = hum:FindFirstChild("Faction")
				local distance = (root.Position - plrRoot.Position).magnitude
				local distanceFromHome = (spawnPos.Value - plrRoot.Position).magnitude
			
				if distance < visionRange and distanceFromHome < abandonRangeFromHome  then
					if faction == nil or faction.Value ~= thisFaction.Value then
						if hum.Health > 0 then
							target = char
						end
					end
				end
			end
		end
	end
end

Okay, I think I found one of the issues… The Dust Bandits only target 1 specific Hungry Bandit or Hungry Bandit Boss at a time. I think these are the first ones on the workspace list, I don’t know why they do that, but im pretty sure that is helpful in figuring out what the issue is here

these is my spawner scripts:

local HungryBandits = game.Workspace.SpawnHungryBandit:GetChildren()
local DustBandits = game.Workspace.SpawnDustBandit:GetChildren()

for i,v in pairs(HungryBandits) do
	local respawn = script.HungrySpawner:Clone()
	respawn.Parent = v
	respawn.Disabled = false
end

for i,v in pairs(DustBandits) do
	local respawn = script.DustSpawner:Clone()
	respawn.Parent = v
	respawn.Disabled = false
end
local serverStorage = game:GetService("ServerStorage")
local rng = math.random(1, 5)

if rng <= 4 then
	enemy = serverStorage:WaitForChild("Hungry Bandit"):Clone()
else 
	enemy = serverStorage:WaitForChild("Hungry Bandit Boss"):Clone()
end

enemy.HumanoidRootPart.Position = script.Parent.Position

local spawnpos = enemy:WaitForChild("SpawnPosition")
spawnpos.Value = script.Parent.Position
local respawntime = 60

enemy.Parent = game.Workspace

enemy.Humanoid.HealthChanged:Connect(function(newHealth)
	if newHealth <= 0 then
		wait(respawntime)
		script.Disabled = true
		script.Disabled = false
	end
end)

and the same but with Dust Bandits

Replace that line with the following, which only targets real players:

if char:FindFirstChild("HumanoidRootPart") and game.Players:GetPlayerFromCharacter(char) then

Sorry, I mean they are npcs fighting each other, not just players. They target players just fine, but I also want them to target each other

Then the condition should be:

if char:FindFirstChild("HumanoidRootPart") and char.Name ~= script.Parent.Name then

and every type of NPC should have a different name(basically NPCs with the same name can’t damage each other)

This does not fix the issue either, as there are multiple types of bandits per faction. In this example, there is “Hungry Bandit” and “Hungry Bandit Boss”. Both of them have different names and appearances but are in the same faction. I have a string value in each npc that says what faction they’re in, and its checking for that. here:

--players do not have a faction bool so it checks for nil
if faction == nil or faction.Value ~= thisFaction.Value then
						if hum.Health > 0 then
							target = char
						end
					end

I did try your fix though, and it did not end up fixing the issue. The Hungry Bandits still do not target Dust Bandits, nor do they target Hungry Bandit Boss, which they should have. I think that the loop itself is breaking somewhere, but i’m not entirely sure where or how.

You can try adding some prints to see what exactly is going on:

--prints under target = char
print("NPC =", script.Parent, "Faction =", thisFaction.Value)
print("Target =", target, "Faction =", (faction and faction.Value))

Aha! That fixed it… Okay, so the problem was here:

if game.Players:GetPlayerFromCharacter(char) then
							local player = game.Players:GetPlayerFromCharacter(char)
							local Endurance = player:WaitForChild("Data"):WaitForChild("Endurance")
							if hum.Health >= (100 - (Endurance.Value/4)) then
								target = char
								--prints under target = char
								print("NPC =", script.Parent, "Faction =", thisFaction.Value)
								print("Target =", target, "Faction =", (faction and faction.Value))
							elseif hum.Health > 0 then
								target = char
								--prints under target = char
								print("NPC =", script.Parent, "Faction =", thisFaction.Value)
								print("Target =", target, "Faction =", (faction and faction.Value))
							end
						end

this elseif needs to be a part of the enclosing if statement, and not the inside one… Oops! Thanks for helping me out here.

2 Likes

Ah, nevermind… It only fixes it sometimes, this is still an issue.

1 Like