NPC that chases players and other NPCs

What do you want to achieve?
I want to make an NPC that chases the nearest target with a humanoid (both players and NPCs) when they get in a certain radius from it.

What is the issue?
I’m not really sure how to do this since i have low scripting experience.

What solutions have you tried so far?
I’ve tried searching for other devforum posts but all of the ones I’ve found just provide a way for an NPC to chase players when what I’m looking for is a way for an NPC to chase both players and other NPCs.

3 Likes

Hello! Here’s how I would go about it:

local RS = game:GetService("RunService")
local target
local hrp = script.Parent.HumanoidRootPart
local maxDistance = 50 --Make this whatever you would like

RS.Heartbeat:Connect(function() --Will constantly run the code below
	for i, v in pairs(workspace:GetChildren()) do --Go through the objects in workspace
		if v:FindFirstChild("Humanoid") and v ~= npc then --If object has a humanoid (so if they are a player or npc)
			local potentialTarget = v --Just to simplify the code, this represents v
			local potentialTargetDistance = (potentialTarget.HumanoidRootPart.Position - hrp.Position).Magnitude
			print(potentialTargetDistance)
			if potentialTargetDistance < maxDistance then
				if not target then
					target = potentialTarget
				else
					if (target.HumanoidRootPart.Position - hrp.Position).Magnitude > potentialTargetDistance then
						target = potentialTarget
					end
				end
				if target then
					npc.Humanoid:MoveTo(target.HumanoidRootPart.Position) --Chase enemy
				end
			end
		end
	end
end)

--Below is a basic system of attacking. If you don't want it, by all means, don't use it.

local debounce = false --To make sure damage isn't given every nanosecond and has a cooldown

hrp.Touched:Connect(function(hit) --When touched
	local humanoid = hit.Parent:FindFirstChild("Humanoid") --Checks if part's parent has a humanoid
	if humanoid then --Checks if part's parent has a humanoid
		if debounce == false then
			debounce = true
			humanoid:TakeDamage(15)
			task.wait(.1)
			debounce = false
		end
	end
end)

Basically, it’s constantly checking if any targets are close enough to attack. If there’s already a target, then it checks if there’s anybody closer. It uses stuff like a pairs loop, and magnitude.

If there’s any problems or you have any questions about how the code works, I’d be happy to answer! If anyone wants to propose improvements to the code, I’d be happy to hear!

4 Likes

Sorry for the late reply but thanks for providing the code! I didnt mention it earlier (cause i was worried i would break devforum rules) but the NPCs are in a folder while the players are in the workspace. I already have a code that makes the table and changed the code up a bit but im not sure how to delete items (when the target dies) or update the table.

for context, heres the table code:

for _, v in ipairs(workspace:GetChildren()) do
    table.insert(objects, v)
end
for _, v in ipairs(workspace.NPCs:GetChildren()) do
    table.insert(objects, v)
end
2 Likes

If you want the AI to not attack dead bodies (which I forgot to add, my bad) you should use if potentialTarget.Humanoid.Health > 0 then and put it under local potentialTarget = v

Anyhow, to remove entries from a table, you can use table.remove. However, you need to insert the position of the entry you want to remove; you cant directly remove the entry using table.remove.

For example, if I have a table here: targets = {[1] = "SomeGuy", [2] = "Goofy NPC"} If I wanted to remove “Goofy NPC” from the table then I would have to do: table.remove(targets, targets["Goofy NPC"]) ; for clarification, targets["Goofy NPC"] returns the position of “Goofy NPC” in the table called “targets”.

1 Like