Why won't #Players:GetPlayers() work?

I’m trying to pick a random player on the server using this line:

local gravelPlayer = Players:GetPlayers()[math.random(1, #Players:GetPlayers())]

But I’m getting an error saying the 2nd argument for math.random is empty. How do I fix this?

4 Likes

Did you define Players as game:GetService(“Players”)?

4 Likes

You’re likely running that line of code when there are no players present. Hence it’s trying to use math.random with arguments 1, 0 which isn’t valid. You can fix this by not running the code until there is at least 1 player present.

5 Likes

^ I just tried this in Studio, got the same result: bad argument #2 to ‘random’ (interval is empty)
The code ran when the server started without any players, when every player loaded it worked in the command line. You can just do something like this. It pauses the script for 3 seconds then runs the math.random line.

if #game.Players:GetPlayers() == 0 then 
	task.wait(3)
end
local randomPlayer = Players:GetPlayers()[math.random(1, #Players:GetPlayers())]
4 Likes

Just pausing it for 3 seconds isn’t sufficient I think?

2 Likes

It’s entirely possible for a server to start up before any players have joined. Perhaps have a players.PlayerAdded:Wait()?

3 Likes

It’s just a sample but a repeat wait() or something like that could work, but yeah you’re probably right

1 Like

Why not just check if there are players on the server before getting a random player?

if #game.Players:GetPlayers() > 0 then 
	local randomPlayer = Players:GetPlayers()[math.random(1, #Players:GetPlayers())]
end

This way it only runs if there are players on the server.
Maybe you can add it inside a PlayerAdded event so it fires when someone joins.

Or put it inside a while loop like this:

while #game.Players:GetPlayers() == 0 do
	task.wait(0.5)
end
local randomPlayer = Players:GetPlayers()[math.random(1, #Players:GetPlayers())]

Or even:

game.Players.PlayerAdded:Wait() -- this will yield the code until anyone joins
local randomPlayer = Players:GetPlayers()[math.random(1, #Players:GetPlayers())]
2 Likes

That while loop does suffice, but is not ideal. The playeradded wait almost works, but if the player joined before, then it will wait for the next player. To account for both of these, do this:

local playerAdded = #game.Players:GetPlayers() > 0 or game.Players.PlayerAdded:Wait()

There will be at least one player after this line, and no loops are needed.

2 Likes

So I think you’re trying to call the function on a number.

#Players:GetPlayers()

Lua might not know whether it has to get the length of the table first or make a table of players first.
You could try doing this instead:

#(Players:GetPlayers())

Because of the parenthesis we first tell Lua to get a list of players before attempting to get it’s length/size.

Alternatively this may also work:

table.maxn(Players:GetPlayers())

or

table.getn(Players:GetPlayers())

which should return the number of present elements.

2 Likes

Maybe use #game.Players:GetChildren() instead of #Players:GetPlayers() as the :GetChildren() method works everytime for me.

It would look like this (Works, tested it)

local Players = Game:GetService("Players")
local gravelPlayer = Players:GetChildren()[math.random(1, #Players:GetChildren())]
2 Likes

This doesn’t make sense. The # operator is for taking the length of a table, so #Players:GetPlayers() can be boiled down to the # operation of the function Players:GetPlayers(). There’s no other way to interpret it other than (#Players):GetPlayers(), which, even though I’m not an expert on how Luau works, wouldn’t work, so it’s a fair guess Luau wouldn’t be built to interpret it like that.

3 Likes

If it did interpret it differently, it would error, as you cannot get the length of a service (how even would you do that, aside from its name?)
Regardless, for the sake of readability, it is generally good practice to wrap multi-clausal phrases of code in brackets when using things like the # operator.

2 Likes

print the #players:GetPlayers and the players:GetPlayers

1 Like

For efficiency reasons, I think it’s better if you run GetPlayers once when you plan to check and store it in a variable in the following way:

function getRandomPlayer(): Player?
	local plrs = game.Players:GetPlayers()
	return #plrs > 0 and plrs[math.random(1, #plrs)] or nil
end

local randomPlayer = getRandomPlayer()
if randomPlayer then
	print(randomPlayer)
else
	print("No player currently in game!")
end

If the error as pointed above is related to code running before a player joins then try adding a delay before fetching the random player:

task.wait(5) --wait for 5 seconds
print(getRandomPlayer()) --try to pick a random player

Also the error might occur because in studio you press Run instead of Play, basically when you start a test but without loading in.

1 Like

Try setting a variable for the amount of players that is added when a player joins.

local Players = game:GetService("Players");
local PlayerCount = 0;

Players.PlayerAdded:Connect(function(player)
      PlayerCount = PlayerCount + 1;
      local gravelPlayer = Players:GetPlayers()[math.random(1, PlayerCount)];
      print(gravelPlayer);
end)

Keep in mind, selecting the gravelPlayer could be called whenever in any function, not just when a player is added as I assume you wouldn’t have use for it there, but more in a round-system.

local function SelectPlayer()
      return Players:GetPlayers()[math.random(1, PlayerCount)];
end;
1 Like

Never concatenate function calls, this allows no check on return values.

-- you already call GetPlayers so why call GetPlayers again?
local gravelPlayer = Players:GetPlayers()[math.random(1, #Players:GetPlayers())]

local playersService = game:GetService("Players");
local players = nil;

local INTERVAL = 1/60;
spawn(function()
	repeat 
		players = playersService:GetPlayers();
		wait(INTERVAL);
	until #players > 1 -- this will have to be greater than one otherwise the math.random() function below will have an empty interval i.e. from 1 to 1
	local gravelPlayer = players[math.random(1, #players)];
	print("Boom");
end)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.