hmmm With your waypoint detector system (the orange sprites) you just have to compare laps and waypoint. But indeed you can't easily evaluate pixel by pixel when a car goes in front of another one. As in a race the space continuum is bent by the shape of the track.
BUT that does not explain why you use different object for NPC.
If you want different name, just use a variable with the name of the NPC
If you want different speed parameter, you can tweak each instance
If you want to count the number of lap or current waypoint for each NPC, just create an instance variable which will old the count for each.
This way you can calculate position easily :
NPC: X greater than FinishLine.X
NPC: is overlapping FinishLine
-> NPC: set backward to true
NPC: X less than FinishLine.X
NPC: is overlapping FinishLine
NPC: [INVERT] is backward
-> NPC: set crossing to true
NPC: [INVERT] is overlapping FinishLine
NPC: is crossing
-> NPC: add 1 to lap
Every tick
-> NPC: set crossing to false
-> NPC: set backward to false
backward booleans are use to check if things goes in the right direction when you cross the finish line.
For waypoint you will just have to check
NPC is overlapping waypoint
-> NPC: set trackPosition to waypoint ID
Then you can calculate relative position with this formula:
Every tick
-> NPC: set racePosition to NPC.lap*waypoint.Count+NPC.trackPosition
if your NPC crossed the line 3 times and is at the 5th waypoint and you have 20 waypoint, his position will be:
3*20+5 = 65
Then you just have to go through all your NPC to check position.
Unfortunately we still don't have a foreach ordered by.
So you will have to do a for loop between 0 and the max number of possible lap*number of waypoint.
For instance if you have a race which last nbLap laps
Global variable inc=1
for 0 to nbLap*Waypoint.Count
Local variable check=0
NPC: racePosition equal loopindex
-> NPC: set place to inc
-> System: set check to 1
Player: racePoistion equal loopindex
-> Player: set place to inc
-> System: set check to 1
System: check equal 1
-> System: add 1 to inc
This assume you run the same kind of calculation for the player object.
Which makes me think that you could also have the player object be the same as the other NPC but just deactivate NPCs by using a boolean you set in property panel.
NPC: is Player
-> activate the race behavior
-> deactivate the bullet behavior
NPC: [INVERT] is Player
-> activate the bullet behavior
-> deactivate the race behavior
-> run the AI
This way you can really have less event to maintain
(Of course if there were families... You could just put NPC and Player into the same family and run all the above stuff just for the family)