Couldn't find anything useful for implementing racing game position ranking

Hey
I’ve been trying to implement racing position for a racing game. I can’t find anything clear on this topic. Why is that? I mean there’s no proper tutorial for this anywhere.

I’ve been trying for a looped Lap race kinda game.
I’m using spline and I got the race progress from that but couldn’t sort the array properly since I’ve separate actor for Player car and AI car.
Can anybody show me a way for this?
I found other answers very unclear, that’s not helping :frowning:

You need two Actor (no special class) arrays… one is the start, second is the sorting.
Iterate over both and compare their Time on a Spline track.

Heres a short example:

Be sure to add each Actor of Cars (Player and AI) to the CurrentPosition array.

3 Likes

You could even improve this by creating a Float:Actor map, where you use the DistanceAlongSpline as Key and the Car Actor as Value.

Then create a SortFloatArrayDescending function in C++ like this:

	UFUNCTION(BlueprintCallable, Category = "Utilities")
		static TArray<float> SortFloatArrayDescending(TArray<float> Array) {
			Array.Sort([](const float& a, const float& b) { return a > b; });
			return Array;
		}

This function can then be used to sort the Keys (Distances) of the Map from High to Low.
Next you could just use the sorted Keys to get the according Car for every Position :slight_smile:

3 Likes

Would add keeping an int with the laps: before sorting add the int with the float DistanceAlongPath.

This could be done in a struct with:
AActor* Racer, int CurrentLap, float DistanceAlongPath and float RaceProgress.

RaceProgress = (DistanceAlongPath + CurrentLap) / TotalLaps.

  • DistanceAlongPath should be % along path, meaning value from 0.f → 1.f

Sort race progress and you’ll get positions regardless of laps.

3 Likes

Off Topic but… I really need to know how you got the rectangular connection-lines for your blueprint setup!

2 Likes

I’ll try this and get back to you, thanks

I’ll try this too, thanks

Plugin called:
Node Graph Assistant

One of my essential Plugins, together with autosize comments and dataTable function library

4 Likes

I don’t know what I did wrong
but it didn’t work for me.
I need to connect this event to tick, right?
or should I create a timer?
Also what exactly the outcome of current position array after the for loop completed?
will it sort the array from high to low or low to high position?

I wouldn’t call this event every tick. Perhaps every 10th or so…

The CurrentPosition Array is an Array of Actors. Just Actors and nothing special.
It should be filled with every Car Actor (including the player Car).

The RankPosition Array is an Array of Actors again. But it can be left empty, since it gets filled via the event and written back to the CurrentPosition Array.

So… CurrentPosition is the Array you use to get all Position Infos from.

The Event should be placed in a BP that is persistent per level… So… the GameState Blueprint is the BP you put it into.
The reason is a bit of foreshadowing.
The GameState is a BP that syncs rules and options from the GameMode to the Clients and vise versa, sends rule and option request to the GameMode.

So… In your GameState Blueprint:
You will need a Point Type variable,too. Set its X to 0 and Y to How many ticks it needs to call the Event (f.e. 10)
In the GameState, add a Tick event.
Now check for the Point Variable X to be >= Y (with a Branch).
If true, call the Ranking Event and set the X back to 0.
If false, add 1 to X.

Edit:
Just in case you wonder, why i use a Point Type Variable…
You can use two Ints, too.
Or a struct holding current and max…

2 Likes

I looked through a couple of answers but found most too complicated.
I have this actually done and is working perfectly and here is some pseudo code:
Spline distance for measuring between 0 and 1 for tracking player on the current lap.
You add 1 in the case that a player is crossing the finish line. You need a direction check atfinish line and checkpoints on the road to have a solid version of this. Then you create an array of all players where you store the distances + laps so you have a float array which says 0.78,1.23,1.67 and so on . Then you do a copy of this and use this in a function what you call every frame. You must not sort this because you in the function you check what Is the highest float so max of array this is your
player place number one . Do it in a loop an delete the value out of the array so that is empty at the End . You can either save this on an array which would be sorted then or what I do I progress this further to my playerstate where I save the player place. Then you just need to bind this player place to a widget and your done

Best regards . hopefully it work for you

You can sort without duplicating, resizing or shuffling down into lower indexes. Just do it in a while loop, swap to back the highest and -1 the index on every loop until == 0.

For example:

The sort function:

Result:


And if you are that curious...

This is from GenericPlatformMath.h:

/**
* Max of Array
* @param	Array of templated type
* @param	Optional pointer for returning the index of the maximum element, if multiple maximum elements the first index is returned
* @return	The max value found in the array or default value if the array was empty
*/
template< class T >
static FORCEINLINE T Max(const TArray<T>& Values, int32* MaxIndex = NULL)
{
	if (Values.Num() == 0)
	{
		if (MaxIndex)
		{
			*MaxIndex = INDEX_NONE;
		}
		return T();
	}
	T CurMax = Values[0];
	int32 CurMaxIndex = 0;
	for (int32 v = 1; v < Values.Num(); ++v)
	{
		const T Value = Values[v];
		if (CurMax < Value)
		{
			CurMax = Value;
			CurMaxIndex = v;
		}
	}
	if (MaxIndex)
	{
		*MaxIndex = CurMaxIndex;
	}
	return CurMax;
}
2 Likes