Best way to get player character from Region3

So, what I want to do is to get the character of all the players that are inside the specific area (except the person who sent this command). I’ve come across two methods using Region3.

The first method, using workspace:FindPartsInRegion3WithIgnoreList() where it ignores the part inside the player who sent this command.

RemoteEvent.OnServerEvent:Connect(function(player)
	local character = player.Character or player.CharacterAdded:Wait()
	local enemies = {}
	local region = Region3.new(Vector3.new(-200, -200, -200), Vector3.new(200, 200, 200))
	local allPart = workspace:FindPartsInRegion3WithIgnoreList(region, {character}, 1000)
	for _, part in pairs(allPart) do
		if part.Name = "HumanoidRootPart" then
			table.insert(enemies, part.Parent)
		end
	end
end)

The second method, using workspace:FindPartsInRegion3WithWhiteList() where it will include only other player character then using white list to check if it’s in that region

RemoteEvent.OnServerEvent:Connect(function(player)
    local all_players = Players:GetChildren()
	local all_players_character = {}
	for _, other_player in pairs(all_players) do
		if other_player ~= player then
			local hmr = other_player.character:FindFirstChild("HumanoidRootPart")
			if hmr then
				table.insert(all_players_character, hmr)
			end
		end
	end

	local enemies = {}
	local region = Region3.new(Vector3.new(-200, -200, -200), Vector3.new(200, 200, 200))
	local allPart = workspace:FindPartsInRegion3WithWhiteList(region, all_players_character, 1000)
	for _, part in pairs(allPart) do
		table.insert(enemies, part.Parent)
	end
end)

The first method looks less complicated, but if there are many other parts inside that certain area. It will need to run through many items from the allPart table in the for loop. Where the second method looks more complicated, but it only runs through only HumanoidRootPart inside the allPart table, which might be faster. However, I am still not sure of both methods, if any of you can come up with a whole different solution that is faster than these methods and can achieve the same goal, please suggest me and I will really appreciate it.

Use the ZonePlus module, it allows for quick and easy detection of players and other objects inside Regions.

1 Like

I never heard of this module before but it looks interesting! Lemme check it out to see how it works.

Alright, I have done some research about ZonePlus and tested it out then compare it with my original method. I do it with trial and error using tick() with different region sizes, for each region size I do it 3 times. Every time I tested there will be 4 people inside the region and some other unnecessary parts that separate around the region. Below is the code block that I used to test 3 different methods:

First method: (Region IgnoreList)

local regionSize = 1000 or 500 or 200 or 50

RemoteEvent.OnServerEvent:Connect(function(player)
	local character = player.Character or player.CharacterAdded:Wait()

    local start_time = tick()

	local enemies = {}
	local region = Region3.new(Vector3.new(-regionSize, -regionSize, -regionSize), Vector3.new(regionSize, regionSize, regionSize))
	local allPart = workspace:FindPartsInRegion3WithIgnoreList(region, {character}, 1000)
	for _, part in pairs(allPart) do
		if part.Name = "HumanoidRootPart" then
			table.insert(enemies, part.Parent)
		end
	end

    print(tick() - start_time)
end)

Second method: (Region WhiteList)

local regionSize = 1000 or 500 or 200 or 50

RemoteEvent.OnServerEvent:Connect(function(player)
    local character = player.Character or player.CharacterAdded:Wait()

    local start_time = tick()

    local all_players = Players:GetChildren()
	local all_players_character = {}
	for _, other_player in pairs(all_players) do
		if other_player ~= player then
			local hmr = other_player.character:FindFirstChild("HumanoidRootPart")
			if hmr then
				table.insert(all_players_character, hmr)
			end
		end
	end

	local enemies = {}
	local region = Region3.new(Vector3.new(-regionSize, -regionSize, -regionSize), Vector3.new(regionSize, regionSize, regionSize))
	local allPart = workspace:FindPartsInRegion3WithWhiteList(region, all_players_character, 1000)
	for _, part in pairs(allPart) do
		table.insert(enemies, part.Parent)
	end
    print(tick() - start_time)
end)
-- idk why it leaves a space like this, but this block continues from above block

Third method: (ZonePlus)

local Zone = require(game.ServerScriptService.Zone) --ZonePlus module
local regionSize = 1000 or 500 or 200 or 50

RemoteEvent.OnServerEvent:Connect(function(player)
	local character = player.Character or player.CharacterAdded:Wait()

    local start_time = tick()

	local enemies = {}
	local zone = Zone.fromRegion(CFrame.new(0,0,0), Vector3.new(regionSize*2, regionSize*2, regionSize*2)) -- Times 2 so it can have a same scale as other method
	local playersArray = zone:getPlayers()
	for _, other_player in pairs(playersArray) do
		if other_player ~= player then
			local character = other_player.Character
			if character then
				table.insert(enemies, character)
			end
		end
	end

    print(tick() - start_time)
end)

Testing

I have tested the performance with 4 people in the game and stayed at the same place and this is what the result looks like:

Region Size = 1000

-- 1st Attempt
Method1 = 0.25443
Method2 = 0.18706
Method3 = 0.00230

-- 2nd Attempt
Method1 = 0.28916
Method2 = 0.18911
Method3 = 0.00233

-- 3rd Attempt
Method1 = 0.20356
Method2 = 0.22486
Method3 = 0.00115

Region Size = 500

-- 1st Attempt
Method1 = 0.02953
Method2 = 0.02844
Method3 = 0.00337

-- 2nd Attempt
Method1 = 0.06852
Method2 = 0.02953
Method3 = 0.00279

-- 3rd Attempt
Method1 = 0.03387
Method2 = 0.03336
Method3 = 0.00257

Region Size = 200

-- 1st Attempt
Method1 = 0.00331
Method2 = 0.00190
Method3 = 0.00132

-- 2nd Attempt
Method1 = 0.00388
Method2 = 0.00539
Method3 = 0.00258

-- 3rd Attempt
Method1 = 0.00297
Method2 = 0.00311
Method3 = 0.00993

Region Size = 50

-- 1st Attempt
Method1 = 0.00175
Method2 = 0.00065
Method3 = 0.00321

-- 2nd Attempt
Method1 = 0.00069
Method2 = 0.00043
Method3 = 0.00107

-- 3rd Attempt
Method1 = 0.00139
Method2 = 0.00029
Method3 = 0.00248

Conclusion

The thrid method, which is the ZonePlus module is insanely fast when calculating on a huge region. The outcomes are completely different from first and second method, they probably using other function with OverlapParams which might process differently from region. However, when the region size become smaller, the ZonePlus method is slowing down (I should not called it slowing down since it stay at pretty much same number as the larger region) Because the first and second methods are a bit more faster in smaller region (which make sense). So, if you doing a safe zone or something that need large region ZonePlus module is actually worth a try (and it also more easier to use). But, in smaller area region, the traditional method Region3 is still usable.

2 Likes