Checking nearby humanoids?

How would I go about checking for nearby Humanoids? I’m creating a ‘chain lightning’ ability, and I want it to chain towards the nearest humanoid within a certain range from the start of the lightning. The potential targets range from actual players, to NPCs located in workspace. I’ve thought about the following methods:

  1. Region3. This is iffy because of the part limit, and I want parts in a certain radius, not a cube area.

  2. Explosion.Hit. I’ve used this event in the past and it works well, but it’s hard to determine when the explosion finishes (AncestryChanged fires ~3 seconds after explosion is created). Without knowing that, it’s hard to determine when the Explosion.Hit property stopped firing (aka all parts fired). Plus, with a BlastRadius of 30+ studs I imagine it’s not too efficient.

  3. Raycasting. Sending out a ton of rays in all directions probably wouldn’t work too well at far distances (~30 to 40 studs).

  4. Raycasting 2. The only other way I can think of would be recursively searching workspace for all humanoids and then sending rays to them to check for obstacles. But I imagine a game with a TON of objects in workspace would make this inefficient. Maybe if I didn’t search recursively, and only the first level of models in workspace? I’d have to make sure not to include any NPCs in other models, but it could work?

Any advice/suggestions on what I should do?

6 Likes
for i, v in pairs(game.Players:GetPlayers()) do
	if (v.Character.HumanoidRootPart.Position - LightningOriginPosition).magnitude <= (max distance) then
		print(v.Name.." can be struck by lightning!")
	end
end

This code will loop through the players, and if they’re within range of the origin of the lightning then it’ll print “Username can be struck by lightning!”)

5 Likes

If you put all of your NPC and character models into a single model, you can avoid searching the entire workspace for humanoids and just search the single model that contains significantly less parts than the entire workspace.

2 Likes

Alternatively, you could use collections service to tag NPCs instead of placing them all under one directory.

14 Likes

This, I think, is the best solution here. It’s probably what I’m going to do for my AoE ability attacks in my game.

1 Like

I’d recommend you account for players with no current character or no HumanoidRootPart.

@Noxielotl That only finds players though. OP wants NPCs as well.


Roblox endorsed models in the Toolbox actually have a module that’s useful for checking for all existing Humanoids in the Workspace. It’s not useful if you’re using Humanoids for other purposes (i.e. displaying clothing items), though.

ROBLOX_HumanoidList.mod.lua

local humanoidList = {}
local storage = {}

function humanoidList:GetCurrent()
	return storage
end

local function findHumanoids(object, list)
	if object then
		if object:IsA("Humanoid") then
			table.insert(list, object)
		end

		for _, child in pairs(object:GetChildren()) do
			local childList = findHumanoids(child, list)
		end
	end
end

local updateThread = coroutine.create(function()
	while true do
		storage = {}
		findHumanoids(workspace, storage) -- I edited this part from game.Workspace
		wait(3)
	end
end)

coroutine.resume(updateThread)

return humanoidList

Alternatively, you can use CollectionService to tag Humanoids. You will most likely have to combine this with Instance::DescendantAdded, check if the descendant’s class is Humanoid, tag it then operate your code based on that tag and CollectionService’s methods. Check @raiinbowjake’s response for the page to CollectionService.

3 Likes

I didn’t see that bit, thanks for pointing it out.

1 Like