How can I determine which position a player starts in before a race begins?

Hello everyone,

What I want to achieve
I’m working on a go-kart type project and I can’t seem to figure out how to determine what place the racers will be in at the beginning of the race. I could just give all the racers random positions, but I don’t think it would be fair. I already programmed what place the racers are in during the race (ex: distance to checkpoints and laps), but what I need help with is determining the initial position that the racers will start in before the race begins. Think of it as Mario Kart online where your previously finished position will be your new starting position when you start the next race.

What’s the issue?
Let’s assume that the server is new and there was no previous race. I would just give the racers random starting positions (ex: if there are four players in the room, I would give each player a random position ranging from 1 to 4 while making sure that a position doesn’t repeat). I think I have that part down.

Here’s what I’m struggling with: Let’s say there are three players racing, and they all finish the race. Player1 gets first place, Player2 gets second place, and Player3 gets third place. Player2 decides to leave the game after he finishes the race. This means that only Player1 and Player3 are remaining, and second place is now vacant. I need to move up Player3 from third place to second place at the start of the race to fill in the gap.

I also need to consider that new players can join at the start of the next new race. I’m thinking that after the vacant places are filled, I can assign the new player’s starting position.

Also, if a player previously finished in first place, I would give him first place right away for the next race, unless he leaves before the next race starts in which I would need to move up second place to first place, as well as move up the rest of the racers as well (3rd would go to 2nd, 4th would go to 3rd, etc).

Here’s what I tried so far:

--SS.PlayersPlaying is a folder that holds folders of players that are going to race for the next race. The name of the folder is the player's name. Each folder contains data such as what position the player is in, what lap he's in, etc.
--SS.PreviousPositions is a folder that stores int values of what position the player was in when he finished the previous race. The name of each int value is the player's name, and the value is the previous position.
local SS = game.ServerStorage
local positionsUsed = {}
for i,v in pairs(SS.PlayersPlaying:GetChildren()) do
	local player = game.Players:FindFirstChild(v.Name)
	if player then
		local previousPositionFound = false
		if SS.PreviousPositions:FindFirstChild(v.Name) and SS.PreviousPositions:FindFirstChild(v.Name).Value > 1 then --this means that the player raced in a previous race and finished
			--find the player that finished a position higher. if he doesn't exist, move the previous finish up

			for i,k in pairs(SS.PreviousPositions:GetChildren()) do
				--there's gonna be a minus one
				--example: if the previous finish was 2nd place, but 1st place doesn't exist, move him up to 1st
				if k.Value == SS.PreviousPositions:FindFirstChild(v.Name).Value - 1 then
					previousPositionFound = true
				end	
			end

			--if the previous position is found, no action is needed, and the player will keep his previous position
			--else, move the player up a position
			if previousPositionFound then
				print("previous position found. giving " .. v.Name .. " " .. SS.PreviousPositions:FindFirstChild(v.Name).Value .. " place")
				v.Position.Value = SS.PreviousPositions:FindFirstChild(v.Name).Value
				positionsUsed[v.Position.Value] = true
			else
				print("previous position not found. moving up a position")
				SS.PreviousPositions:FindFirstChild(v.Name).Value = SS.PreviousPositions:FindFirstChild(v.Name).Value - 1
				v.Position.Value = SS.PreviousPositions:FindFirstChild(v.Name).Value
				positionsUsed[v.Position.Value] = true
			end
		elseif SS.PreviousPositions:FindFirstChild(v.Name) and SS.PreviousPositions:FindFirstChild(v.Name).Value == 1 then
			print("giving " .. v.Name .. " first place")
			v.Position.Value = SS.PreviousPositions:FindFirstChild(v.Name).Value
			positionsUsed[v.Position.Value] = true
		else
			local random = 0
			repeat
				local random = math.random(1,#SS.PlayersPlaying:GetChildren())
				wait()
			until not positionsUsed[random] 
			v.Position.Value = random
			positionsUsed[random] = true
		end
	end
end
SS.PreviousPositions:ClearAllChildren() --reset. will be refilled when the new race is over

I don’t believe the code I drafted would fill in two gaps, either. Say Player1 finishes in 1st, Player2 in 2nd, Player3 in 3rd, and Player4 in 4th. Players 2 and 3 leave, which means player 4 would need to move up 2 positions to get to 2nd place when the race begins.

This code will eventually be used to determine the location each player spawns in the map. If the player previously finished in first place, he will spawn closer to the finish line than the other players. I already know how to spawn the players in according to their previous positions, but it’s just a matter of figuring out what the player’s position should be before the race starts.

The above code serves its purpose, but I’m sure it has some stuff that needs to be worked out. If you need anything to be explained a bit more thoroughly, let me know and I’ll try my best to explain further. Thanks for your help in advance.

1 Like