What is the most performant way to detect if multiple players are in close proximity to one another?

  1. What do you want to achieve?
    I want to find out the most performant and reliable way to determine when a group of players are standing within a given proximity to each other, specifically to determine if 3 or so players on the same team are standing near each other in order to play a song where they are, and stop the song when they move apart, or die.

  2. What is the issue?
    I’m not really sure what would be the best way to go about doing this; while checking magnitude between two players is simple as pie, how could it be done to check to multiple players and have them all generate a single “count” of how many players happen to be next to each other at this exact moment? If I looped through multiple characters, how could I avoid making them “double count”? Would this be bad on performance? Etc.

  3. What solutions have you tried so far?
    I’ve thought of breaking the map up into region3 “chunks”, doing a loop every 0.25 seconds or so using a simple magnitude check to only check the chunks closest to actual players, then for each “valid” chunk near players count how many characters are standing in the given chunk using findpartsinregion3. If it’s > 3, play the song at their location. The issues I see with this are:

  • It may not be performant, as the map is quite large.
  • Since players are on moving airships, their chunk position would constantly change.
  • Players might visibly be standing close together, but one player might technically happen to be in a bordering chunk, causing unreliability.
  • I wouldn’t really be sure of how to “track” the players to move the music sound part’s position to stay between them, and also break up the music if they move too far apart or die.

What would be the best approach for going about this?

The new WorldRoot:GetPartBoundsInRadius function, definitely.

Would this not be more-or-less just another way of doing the “chunk” method I mentioned before?

Sorry if my post wasn’t specific, I’m more worried about the actual logic of how to go about handling the detection/management of players, moreso than the literal code function(s) I’d use.

The new GetPartBoundsInWhatever functions are all just as performant as simple raycasts. They also allow you to filter out instances that aren’t characters with the new overlapParams argument.

It would be similar to what you described per se, however it’s not too performant cycling through players and comparing magnitudes multiple times per second, and since this would be on the server, you’d want to put as less strain as possible on the server for overall performance - and these functions work great with any map size.

local players = game:GetService("Players")

local function getCloseCharacters(minDistance)
	local closeCharacters = {}
	for _, player in ipairs(players:GetPlayers()) do
		for _, otherPlayer in ipairs(players:GetPlayers()) do
			if player ~= otherPlayer then
				local distance = player:DistanceFromCharacter(otherPlayer.Character.PrimaryPart.Position)
				if distance <= minDistance then --20 studs.
					if not table.find(closeCharacters, player) then
						table.insert(closeCharacters, player)
					if not table.find(closeCharacters, otherPlayer) then
						table.find(closeCharacters, otherPlayer)
	return closeCharacters

local closeCharacters = getCloseCharacters(20) --20 studs.


What about using an invisible cylinder as part and around each characters as a way to test collision between those “bubbles”. The radius of the cylinder is the distance at which you wish your effect to start.

That is what I would try.

Stay Creative


I actually did just that for auto lit and dim lights model I did.

Stay Creative

Simple loop iteration through :GetPlayers() will almost certainly be faster, so long the amount of players is below ~800 or so. The reason for this is that simple Magnitude-check loops are very inexpensive, and solutions such as OverlapParams are a lot more expensive unless you have several thousand objects to loop through.