# Race system with player positions, 1st, 2nd, etc

1. What do you want to achieve? Keep it simple and clear!
I’m trying to make a race system where the person farthest in the game is 1st place, and the person behind him is 2nd place, etc.

2. What is the issue? Include screenshots / videos if possible!
I can detect how far away the person is to the next checkpoints via magnitude, however I am unsure how proceed with detecting if two players are on the same checkpoints and which is first with said magnitude and sorting who is 1st, 2nd, 3rd. Also, tables aren’t my expertise.

3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
I have tried looking for solutions, however there is very few, and the ones that I did find, were not very much help as either they talked about putting many detection parts which would be very tedious and would not work for my game, or were way too complicated for me to understand.

3 Likes

You can use magnitude like you said, here is an example of what I would do.

``````local firstPlace= [[ your values in replicated/server storage named the correct positions in race (FirstPlace, SecondPlace, etc.) ]]

local secondPlace= [[ your values in replicated/server storage named the correct positions in race (FirstPlace, SecondPlace, etc.) ]]

((thirdplace, fourth, 5, etc..))

if RaceCar.PrimaryPart.Position.Magnitude > OtherRaceCar.PrimaryPart.Position.Magnitude then
firstPlace = RaceCar.Name
secondPlace = OtherRaceCar.Name
end`````````

Maybe I’m not understanding it right, but wouldn’t that only work for one checkpoint?

Here’s my code for detecting magnitude from the player to the next checkpoint:

``````game.Players.PlayerAdded:Connect(function(player)
wait()
end

for _, v in pairs(game.Workspace.Checkpoints:GetChildren()) do
for _, player in pairs(game.Players:GetPlayers()) do
local character = player.Character
if not character then
continue
end
local HRP = character:FindFirstChild("HumanoidRootPart")
if not HRP then
continue
end
local hrppos = HRP.Position
local distance = (hrppos - pos).Magnitude
print(distance)
end
else
local pos = game.Workspace.Checkpoints:FindFirstChild("0").Position
for _, player in pairs(game.Players:GetPlayers()) do
local character = player.Character
if not character then
continue
end
local HRP = character:FindFirstChild("HumanoidRootPart")
if not HRP then
continue
end
local hrppos = HRP.Position
local distance = (hrppos - pos).Magnitude
print(distance)
end
end
end
end
end)
``````

I think you can put all the current values in a table, then use table.sort() to sort it out, then get the first three people in descending order.

This would requre alot more if-else statements, because if there would be 50 players, how much if-else would you write for comparing everyone’s value?

1 Like

I answered this same question about 2 weeks ago but I assume my response falls under the category that it was either too tedious or too complicated (How to detect who’s 1st, 2nd, 3rd, etc in my racing game - #6 by uwuCulturist)

If you want a simple answer for how to store which checkpoint a player is on, you can use a table like so

``````local Players = game:GetService("Players")
local PlayerProgress = {

}

-- Setting every player's progress to 0 at the start of the race

for i,v in next, Players:GetPlayers() do
PlayerProgress[v.Name] = 0
end

--[[ Now the player progress will look like this
{
PlayerName1 = 0,
PlayerName2 = 0,
PlayerName3 = 0,
PlayerName4 = 0,
}
]]
``````

To add or remove progress from a player, do this

``````     PlayerProgress[PlayerNameHere] += 1 -- Adds 1 progress
PlayerProgress[PlayerNameHere] -= 1 -- Subtracts 1 progress
``````

Once a player passes a checkpoint (Checkpoint.Touched signal), add 1 to their progress or set the progress to some value that you can easily sort.

Because you’re dealing with a dictionary rather than a list, you should refer to Dictionary Sorting - #8 by Complextic to see how to sort it

3 Likes

Hmm… Can’t we just simply use table.sort() ? Also, what if we just need to find who’s in lead, like who is the most closest ? So your post isn’t that reliable. It just checks who has the highest number of checkpoint. He doesn’t want who has the highest number of checkpoints, because it would be a problem as well if two persons have same checkpoint.

# You can use a table to store the players and their positions.

You can use a table to store the players and their positions.

``````local players = {}

players[player] = 0
end

local function removePlayer(player)
players[player] = nil
end

local function updatePlayerPosition(player, position)
players[player] = position
end

local function getPlayerPosition(player)
return players[player]
end
``````

You can then use a table to store the positions and the players in them.

``````local positions = {}

if positions[position] == nil then
positions[position] = {}
end

table.insert(positions[position], player)
end

local function removePlayerFromPosition(player, position)
if positions[position] == nil then
return
end

for i, playerInPosition in ipairs(positions[position]) do
if playerInPosition == player then
table.remove(positions[position], i)
break
end
end
end

local function getPlayersInPosition(position)
return positions[position]
end
``````

Please see the OP’s post. He wants to find the magnitude and this can be easily done using table.sort() I guess…

What software u using?

That’s what I plan on using, however I have very little to no experience with tables, I only know the basics such as insert, delete, floor, find, and a bit more. I would need help with sorting like you said and probably alot more.

It’s ez. Lemme explain

table.sort() sorts a table. You’ll easily understand with this example

``````local t = {1,2,3,4,5} --create a table

local function descending(a,b) --this is a function used to choose whethere to sort the table in ascending or descending
return a > b
end

table.sort(t, descending) --sorts it and the function determines whether it should sort in ascending or descending order.

for i, value in pairs(t) do
print(value) -- this will print as descending order as we sorted like that
end

``````

Hm, alright I think I understand sorting, but how would I assign a player to a position though? Would I use a dictionary like fox said?

table.sort only works on lists/arrays, not dictionaries

also if you look at the post I linked, it explains how to use table.fort on a dictionary

if you’re wanting to use table.sort natively, there won’t be a way to add a key, you’re just going to be left with a sorted table of numbers without any way to tell which player it relates to

Easiest way to do this it to keep track of the current checkpoint and the amount of laps a player has completed.

You would want the checkpoints to be around 10 studs apart and follow the track.

You also need to track which checkpoint the player is currently at, as well as track how many laps a player has completed.

Next up you just need to write a simple loop that checks which player has Completed the most laps and is furthest along the list of Checkpoints.

Your post also don’t really explain the real problem OP have as I stated above. It just seems like promoting a topic here (sorry if I’m rude). It just tells about getting player’s checkpoint. What if many players have same checkpoint? Then how your code can work ? OP actually wants to get the magnitude…

Sorry, it’s my time to sleep, will tell you how to convert it into arrays.

For now just get the idea

``````local t = {}

for i=1, 7 do --example
t[i] = something --I'll tell the whole process tomorrow.
end
``````

Till then, stay tuned!

``````local t = {}
local playertable = game.Players:GetPlayers()

for i=1, #game.Players:GetPlayers() do
t[i] = playertable[i]
end

function descending(a,b)
return a > b
end)

table.sort(t, descending)
``````

That should pretty much do your work!

To determine the race position of players based on their progress through checkpoints, you can use a table to store the players’ distances from the checkpoints and then sort the table based on those distances. Here is an example code that can help you get started:

``````local checkpoints = game.Workspace.Checkpoints:GetChildren()

local playersDistances = {} -- table to store player distances from the checkpoints

-- function to update the playersDistances table
local function updatePlayerDistances()
for _, player in pairs(game.Players:GetPlayers()) do
local character = player.Character
if character then
local nearestDistance = math.huge
for _, checkpoint in ipairs(checkpoints) do
local distance = (character.HumanoidRootPart.Position - checkpoint.Position).Magnitude
if distance < nearestDistance then
nearestDistance = distance
end
end
playersDistances[player.Name] = nearestDistance
end
end
end

-- call updatePlayerDistances() every second
while wait(1) do
updatePlayerDistances()
end

-- function to sort the playersDistances table and print the race positions
local function printRacePositions()
local sortedPlayers = {}
for playerName, distance in pairs(playersDistances) do
table.insert(sortedPlayers, {playerName, distance})
end
table.sort(sortedPlayers, function(a, b) return a[2] < b[2] end)
for i, playerData in ipairs(sortedPlayers) do
local playerName, distance = playerData[1], playerData[2]
print("Player " .. playerName .. " is in " .. i .. " place with a distance of " .. distance)
end
end

-- call printRacePositions() every 10 seconds
while wait(10) do
printRacePositions()
end
``````

This code updates the playersDistances table every second with the nearest checkpoint distance for each player, and then sorts the table every 10 seconds to print the race positions. Note that this is just a starting point and you may need to modify this code to fit your specific game needs.

So looking at the solutions here, they are somewhat confusing. Please allow me to shine some light on this issue.

Like OP said, he already knows how to sort players via magnitude. The real issue here is that he wants to add checkpoints on top of magnitude and probably loops too.

While provided solutions may work, they are unnecessarily complicated. Best way to go about this is to provide a custom sort function to `table.sort`:

``````-- keep all player data here
local Entries = {}

-- add a new entry when character is spawned

table.insert(Entries,{
player = plr,
root = chr.HumanoidRootPart,
checkpointRef = somePart, --add a starting checkpoint part here
checkpointValue = 1 -- first checkpoint has a value of 1
loop = 0, -- optional loops
}
end)
-- remove an entry when player leaves or despawns
plr.CharacterRemoving:Connect(function()
for i, entry in pairs(Entries) do
if entry.player == plr then
table.remove(Entries,i)
break
end
end
end)

end)

-- adjust the checkpoint with this function
local function ChangeCheckpoint(plr,newCheckpoint,newCheckpointValue)
for _, entry in pairs(Entries) do
if entry.player == plr then
entry.checkpointRef = newCheckpoint
entry.checkpointValue = newCheckpointValue
break
end
end
end

-- adjust the loop with this function
--EDIT: Corrected the name of the function
local function ChangeLoop(plr,newLoopValue)
for _, entry in pairs(Entries) do
if entry.player == plr then
entry.loop = newLoopValue
break
end
end
end

-- finally the sort function
local function CustomSort(entryA, entryB)
--first check the loop
if entryA.loop ~= entryB.loop then
-- players have different amount of loops, return the result
return entryA.loop < entryB.loop
-- if loop is the same, check if the checkpoints are different.
elseif entryA.checkpointValue ~= entryB.checkpointValue then
-- players have different checkpoints, return the result (each checkpoint has a different value)
return entryA.checkpointValue < entryB.checkpointValue
else
-- finally if checkpoints are the same, see which player is further away from said checkpoint
return (entryA.root.Position - entryA.checkpointRef.Position).Magnitude <
(entryB.root.Position - entryA.checkpointRef.Position).Magnitude
end
end

-- Example of sorting loop each second (adjust if needed)