Enemy/NPC player detection

Newb here and I trying to determine “best” pattern for a NPC to detect a player.
I’m currently using raycasting to have the NPC basically look for a player, but I also want the NPC to be able to maybe “hear” a player behind them. I thought about putting an invisible part around the NPC and detect collision, but that doesn’t feel right.

I see a lot of post that loop through all players to find ones “close” and that seems like a unnecessary loop. I would rather it work more organically and avoid looping unless performance wise that is best approach.

I assume this is a design pattern that has already been solved, but having trouble finding it.

thanks for any advice/help.

voss.

5 Likes

You’re looking for the pathfinding service. You can pick a player and compute a path to their humanoidrootpart, etc etc.

1 Like

There are 2 other options of detecting players behind/around the NPC.
You can create Region3s behind/around the NPC and use FindPartsInRegion3 to get the players in the Region3.
You can also create a hitbox part behind/around the NPC and use GetTouchingParts to get the players in the hitbox.

However:
Looping through players and computing the distance from them will be less expensive, as it’s just a magnitude comparison from the player’s HumanoidRootPart position to the NPC’s position. You can use Player:DistanceFromCharacter to reduce overhead from Vector3 arithmetic.

Region3s require more math operations to compute which parts are inside it, and the same goes with GetTouchingParts. Read the “How do Region3 checks work?” section on the FindPartsInRegion3 page.

2 Likes

So sounds like you are saying there is no need to try to get fancy with this and retrieving/looping through all the players is the best approach to detect players and just determine based on position diff if they are in line of site or behind ?

Also use tags, you can tag humanoids if you ai needs to find something other than the player.

Is a tag the same thing as setting a “value” ?

game.Players.PlayerAdded:Connect(function(player)

local isFlag = Instance.new("BoolValue")
isFlag.Name = "IsFlag"
isFlag.Parent = player
isFlag.Value = false

end)

thanks for the help

Sorry for the super late reply but no tagging works like this:

game:GetService("CollectionService"):AddTag(model, "Humanoid")

In my game all AI get their humanoids tagged because my mobs will fight each other if they are not part of the same ‘Faction’.
And then you can use

for _, object in pairs(game:GetService("CollectionService"):GetTagged("Humanoid")) do

to find those Humanoids.

1 Like

Awesome.
That’s good to know.
I can replace some bad code I had.
thanks.

No problem and remember you can tag other stuff other than Humanoids depending on what you need.

1 Like

How do we know for sure which method is the least burden: (1) Region3 (2) Invisible hitbox touched (3) Loop & computing magnitude?

Personally, I would just loop through each player and compute the magnitude.

From my experience, depending on .Touched is terrible and inaccurate. Not a good idea.
For Region3 though, I can’t say anything about it because I’m not familiar with it.

Just go with either Region3 or Magnitude.

1 Like

FindPartsInRegion3 is deprecated. He has to use Overlap Params instead. Source: Introducing OverlapParams - New Spatial Query API

2 Likes