Cleaner,better ways to give npcs awareness?

when I make non humanoid npcs I usually use one big invisible cancollide false part thats hooked up to either a touched function or “gettouchingparts” which the npc uses to sense things around it. this is fine for the most part but even if I make said part as light as possible it still makes it difficult for npcs to move around as it still carries some mass. the only other method I know of is raycasting but thats not practical to use when I need a large area to be seen.

what kinds of other methods are out there? what do popular games like visteria use for their NPCs?

1 Like

There is a property under BaseParts called Massless, which you can toggle to nullify the mass. Even then, though, this kind of a solution might be pretty hard hitting on performance.

One of the few more renown methods of searching for nearby items is a magnitude check between a point and the NPC’s root. Often this can be a table of other Humanoids or whatever. You collect any humanoids up into an array and then calculate the distance between the NPC and the root of each humanoid in that array.

An alternative I know of is using Region3s to detect parts with Workspace:FindPartsInRegion3. You could even lessen the amount of times you call this method to the frequency of how long it takes for the NPC to reach a little less than half the distance the Region3 covers, or just checking with magnitudes if this distance was reached over a smaller interval, and calling the function regardless if it hasn’t been for a long time, so as to stay efficient.

I didnt quite get the hang of using region3 when I tried to use it, but colbert`s idea with magnitude seems interesting, but how would I use that to find parts in an area? do I still need to use an invisible part to define the area?

I made a small thing about magnitude checks and Region3s, I hope it helps!

About Magnitudes

For magnitude checks, you would need a collection of parts to check first for the NPC to be aware of. It’s useful if you already lessened that collection to something manageable. You can’t just use workspace:GetDescendants to get every part in workspace and check their distance, because that would lag the game a whole lot. Unless you are checking a smaller group of parts, like players’ characters, you should not use this method.

If you find the difference of two Vectors and get the .Magnitude of the result, you can essentially find the distance between the two points:

local dist = (Position1 - Position2).Magnitude
-- or...
local dist = (Position2 - Position1).Magnitude

Using this distance formula, you can figure out how far away objects are from a position, and factor that into your NPC’s decisions, like looking at a player or something like that:

if (NPC.Position - Player.Position).Magnitude < 20 then
	MakeNPCLookAt(Player.Character)
elseif NoOtherPlayersFound() then
	StopNPCLook()
end

NPC.Position and Player.Position would (obviously) be replaced by their respective humanoid root parts/heads/torsos

For this specific example, there is a better way of doing it:

local dist = Player:DistanceFromCharacter(NPC.Position) 

if dist ~= 0 and dist < 20 then
	MakeNPCLookAt(Player.Character)
elseif NoOtherPlayersFound() then
	StopNPCLook()
end
About Region3s

Region3s don’t loop through every single part in workspace, somehow, unlike magnitude checks would have to under normal circumstances. It is also a Roblox method, meaning it executes in C++, so it’s definitely faster than looping through every part in workspace if you don’t have any way to lessen the pool of parts to search.
Region3s are simple enough to use, they can be created using Region3.new and a minimum/maximum bound Vector3:

local r3 = Region3.new(minBound, maxBound)

You can use a formula like this to get a Region3 around your NPC:

local r3 = Region3.new(NPC.Position - offset, NPC.Position + offset)

Keep in mind that NPC.Position isn’t a valid property (obviously), you have to use the humanoid root part’s position (or whatever limb you want really) instead.

The size of offset could probably be based on the humanoid’s walk speed, but it can be larger if you need it to be:

local offset = Vector3.new(1,1,1) * Humanoid.WalkSpeed

The method Workspace:FindPartsInRegion3 takes three arguments, the Region3 to use, a part (and its descendants) it should ignore, and how many parts to search for before stopping:

local Parts = workspace:FindPartsInRegion3(r3, ignore, num)
  • r3 was pretty much already defined in the above blocks
  • ignore will probably just be the NPC’s character
  • num can be decided by you, the smaller it is, the more efficient it will be.

This method will return an array of parts that you can use like :GetTouchingParts.

The more efficient cousins of FindPartsInRegion3 is:

1 Like

thanks, you made region3 a lot easier to work with.

1 Like