How do racing games work out the positions?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Tato64

Hey gang, so basically i was trying my hand on making a game kind of like “Mario Kart 64” (You know, with beautiful Sprite3D racers and stuff)

I got it working pretty much, fooled around for a while, had some fun, but then it hit me…

How do racing games code for vehicle positions? Pretty much every racing game in existence has something in the GUI showing your place, and this thing updates in real time.

I thought up a few methods but none sound like the best or most efficient way of doing it, the most convincing one was having some kind of pathfinding AI trying to “travel” from each car to the finish line and then “sorting” the cars from closest to furthest.

But anyways… how does it work?

Thanks in advance!

Are you trying to get the progress of the racers along the track?
If so you can use checkpoints, it’s a common way to measure a player’s progress.
You can also use a path to define the track for more flexibility and precision.

Bubu | 2021-04-15 01:15

Im just trying to know how “most” (I figure not all games do it the same way) check for each car’s position, i dont care about track progress %, just who’s coming in first place, second place, third, and so on.

I figured checkpoints carefully placed along the track and a simply using “distance_to” (No pathfinding or fancy stuff) to the next checkpoint + the cumulative distances between the remaining checkpoints, and then the lowest number is first and so on.

But i want to know if there are better ways

Tato64 | 2021-04-15 01:48

I tried to calculate the ranking of players using the track progress because it doesn’t need a lot of work.

I created a path and simply trace the track. Then made some PathFollow nodes to track down the players’ progress. Then finally, sorted the players based on their progress.

So even though you don’t need the players’ progress, it’s helpful for sorting the players.

One problem though is that I haven’t figured out how to get the percentage of the path based on a given location.

So I used a proximity limit to make it simple, it’s accurate and works well if you want to sort the players.

Bubu | 2021-04-15 02:15

Sounds reasonable, if you can share a bit of code or pseudocode how-to i’d appreciate a lot!

Tato64 | 2021-04-15 02:44

Sure, but my implementation might be buggy if it’s not tweaked properly. So be careful and you might help me to improve it as well.

Bubu | 2021-04-15 02:48

There are several other reasons you may want to place checkpoints on each track anyway:

  • Preventing players from advancing a few meters, going backwards, then crossing the finish line to count as a lap.
  • Disallow cutting through the track’s scenery.
  • Placing players who accidentally leave the track back on the track.

Calinou | 2021-04-15 15:07

Actually, I used two checkpoints to prevent the players from reversing and count the laps but I didn’t include this part of the script for simplicity.

I used a path in combination with checkpoints to add precision and make the progress look continuous.

My game also had barriers so the players cannot leave the track anyway.

Your game might be structured differently but this is how I made mine.

Bubu | 2021-04-15 15:28

:bust_in_silhouette: Reply From: Bubu

Here is the code I used for my game:

extends Control

var step = 1 #Largest distance allowed for approximation.
var path_step = 0.0001 #The smaller, the more accurate.
var p1_position = Vector3()
var p2_position = Vector3()
var p1_progress = 0
var p2_progress = 0
var p1_laps = 0
var p2_laps = 0

func _process(_delta):
#	Player 1 progress
	#Calculate the player's position based on the curve.
	p1_position = $Track/Path.get_curve().get_closest_point($Player1.translation)
	#Increment the PathFollow node until it's close to the player's position.
	while ($Track/Path/P1PathFollow.translation - p1_position).length() > step:
		$Track/Path/P1PathFollow.unit_offset += path_step
	#Get the progress from the PathFollow's Offset, include laps as well.
	p1_progress = p1_laps + $Track/Path/P1PathFollow.unit_offset
#	Player 2 progress
	p2_position = $Track/Path.get_curve().get_closest_point($Player2.translation)
	while ($Track/Path/P2PathFollow.translation - p2_position).length() > step:
		$Track/Path/P2PathFollow.unit_offset += path_step
	p2_progress = p2_laps + $Track/Path/P2PathFollow.unit_offset
	
	if p1_progress > p2_progress:
		$RankLabel.text = "1: Player 1\n2: Player 2"
	elif p2_progress > p1_progress:
		$RankLabel.text = "1: Player 2\n2: Player 1"

Check out this image.