How to make a 1st, 2nd, 3rd place racing system roblox studio

I Am Making a racing running game and I want to have a system for all the players to show what place they are in. So far I made a system that gets all of their current positions and put it as integer values inside of a folder but have no clue on how to organize this information to rank it

I’m asking for help on how would I approach and how would I rank the data that I have. Thank you.

If it’s a straight race (not like a circle race) then you could do this:

I recommend doing this on each client and not the server just to prevent unnecessary load on the server (and this will involve GUI’s anyways).
So create a blank table which will track each character in the race and their distance.

-- Something like this:
local Distances = {}
for i, char in ipairs(RaceCharacters) do
	local plr = Players:GetPlayerFromCharacter(char)
	local distance = (char.Position - FinishLine.Position).Magnitude -- player's distance
	local plrdistance = {plr.UserId, distance} -- First index is the key, second is the distance
	table.insert(Distances, distance) -- Inserting it into our distances table
end

This allows us to track each player’s distance and which player accounts for that distance.

Now every heartbeat, we just have to check for the lowest distance

RunService.Heartbeat:Connect(function()
	local lowestDistances = {}
	for i, distance in ipairs(Distances) do -- checking for each player's distance
		table.insert(lowestDistances, i, distance[2]) -- remember, the second index holds their distance from the finish line and "i" will be used to index the player later
	end
	local checkLowestDist = table.unpack(lowestDistances) -- unpacking table so we check minimum value
	local lowestDist = math.min(checkLowestDist)
	
	local lowestDistIndex = table.find(lowestDistances, lowestDist) -- Finding that dist in the table
	local userIdLowestDist = Distances[lowestDistIndex][1] -- remember, the first index holds the player's userId
	
	local ClosestPlayer = Players:GetPlayerByUserId(userIdLowestDist) -- Now we have the player
end)

Great, now we have the closest player

Now this optional, but you could take it a step further by checking the second, third and so on.

RunService.Heartbeat:Connect(function()
	local lowestDistances = {}
	for i, distance in ipairs(Distances) do -- checking for each player's distance
		table.insert(lowestDistances, i, distance[2]) -- remember, the second index holds their distance from the finish line and "i" will be used to index the player later
	end
	local checkLowestDist = table.unpack(lowestDistances) -- unpacking table so we check minimum value
	local lowestDist = math.min(checkLowestDist)
	
	local lowestDistIndex = table.find(lowestDistances, lowestDist) -- Finding that dist in the table
	local userIdLowestDist = Distances[lowestDistIndex][1] -- remember, the first index holds the player's userId
	
	local ClosestPlayer = Players:GetPlayerByUserId(userIdLowestDist) -- Now we have the player
	---------------------------------------
	lowestDistances[lowestDistIndex] = nil -- We do this instead of table.remove so that the indexes are the exact same
	local secondLowestDist = table.unpack(lowestDistances)
	local lowestDist = math.min(checkLowestDist)

	local secLowestDistIndex = table.find(lowestDistances, lowestDist) 
	local secondUserIdLowestDist = Distances[lowestDistIndex][1]

	local SecibdClosestPlayer = Players:GetPlayerByUserId(userIdLowestDist) -- Rinse and repeat
end)

Now you could put that in a for i, loop until you get all the player’s positions in the race.

RunService.Heartbeat:Connect(function()
	local lowestDistances = {}
	for i, distance in ipairs(Distances) do -- checking for each player's distance
		table.insert(lowestDistances, i, distance[2]) -- remember, the second index holds their distance from the finish line and "i" will be used to index the player later
	end
	local checkLowestDist = table.unpack(lowestDistances) -- unpacking table so we check minimum value
	local lowestDist = math.min(checkLowestDist)
	
	local lowestDistIndex = table.find(lowestDistances, lowestDist) -- Finding that dist in the table
	local userIdLowestDist = Distances[lowestDistIndex][1] -- remember, the first index holds the player's userId
	
	local ClosestPlayer = Players:GetPlayerByUserId(userIdLowestDist) -- Now we have the player
	---------------------------------------
	for i = 1, #PlayersInRace do
		lowestDistances[lowestDistIndex] = nil -- We do this instead of table.remove so that the indexes are the exact same
		local secondLowestDist = table.unpack(lowestDistances)
		local lowestDist = math.min(checkLowestDist)

		local secLowestDistIndex = table.find(lowestDistances, lowestDist) 
		local secondUserIdLowestDist = Distances[lowestDistIndex][1]

		local SecibdClosestPlayer = Players:GetPlayerByUserId(userIdLowestDist) -- Rinse and repeat
	end
end)

Anyways, hope I didn’t make it too complicated.

Final code:

local Distances = {}
for i, char in ipairs(RaceCharacters) do
	local plr = Players:GetPlayerFromCharacter(char)
	local distance = (char.Position - FinishLine.Position).Magnitude
	local plrdistance = {plr.UserId, distance}
	table.insert(Distances, distance)
end

RunService.Heartbeat:Connect(function()
	local lowestDistances = {}
	for i, distance in ipairs(Distances) do -- checking for each player's distance
		table.insert(lowestDistances, i, distance[2]) -- remember, the second index holds their distance from the finish line and "i" will be used to index the player later
	end
	local checkLowestDist = table.unpack(lowestDistances) -- unpacking table so we check minimum value
	local lowestDist = math.min(checkLowestDist)
	
	local lowestDistIndex = table.find(lowestDistances, lowestDist) -- Finding that dist in the table
	local userIdLowestDist = Distances[lowestDistIndex][1] -- remember, the first index holds the player's userId
	
	local ClosestPlayer = Players:GetPlayerByUserId(userIdLowestDist) -- Now we have the player
	---------------------------------------
	for i = 1, #PlayersInRace do
		lowestDistances[lowestDistIndex] = nil -- We do this instead of table.remove so that the indexes are the exact same
		local secondLowestDist = table.unpack(lowestDistances)
		local lowestDist = math.min(checkLowestDist)

		local secLowestDistIndex = table.find(lowestDistances, lowestDist) 
		local secondUserIdLowestDist = Distances[lowestDistIndex][1]

		local SecibdClosestPlayer = Players:GetPlayerByUserId(userIdLowestDist) -- Rinse and repeat
	end
end)
3 Likes