Racing Game - Who's in front?

Hi guys, I was wondering how I could go about figuring out which car is in front of another car on a track? I really don’t want to use checkpoints because I’m also going to need this code for cat & mouse races which are based entirely on the distance between one car and the car behind it. How can I compare two cars and determine who’s in front & the distance between them? Is there a mathematical formula I can use? Thanks!
-big

1 Like

One easy way to determine the distance between two cars is to have a point in the same spot on each par (Say, the driver seat) And get the magnitude of the Second position, minus the First position

local Car1Pos, Car2Pos = workspace.CarOne.DriverSeat.Position, workspace.CarTwo.DriverSeat.Position;
local Distance = (Car2Pos - Car1Pos).magnitude;
print(Distance);

If you’re having them go around a typical NASCAR track, the magnitude will be different on the straight ways, vs if they cars are going down opposing sides.

Now, as for judging who is in first place, I’m not entirely sure what the best or easiest way to do this would be without using checkpoints. You could try asking @GeorgeOfAIITrades how he does it .

2 Likes

Check this thread out:

1 Like

All honestly, you’re gonna want to do checkpoints for the races. For particular cat & mouse races, you’ll just have to have a different setup to go about with. Need for Speed Underground 2 in particular had a cat & mouse style mode, where I’m pretty darn sure they had to do some wildin ideas to calculate who’s in first, and when because there was no set circuit, and you could change direction and keep the lead, and it was nutsssssss

But yea, definitely just do checkpoints. Trust me. That being said, not sure if my way of doing checkpoints is the most efficient, so might not wanna take my system. And for calculating the distance, MrLonely said it best, but you might need a few tweaks. His code is taking the distance from the center of each seat and comparing that, so elevation changes are including in that formula, and you’ll never get it to hit 0 unless they’re inside each other. The best way to go about this is probably give it like a 20 or 30 stud level of closeness. If the seats are that close, they’re pretty much on top of the person. I would personally use

local Car1Pos, Car2Pos = (workspace.CarOne.VehicleSeat.Position.X + workspace.CarOne.VehicleSeat.Position.Z), (workspace.CarTwo.VehicleSeat.Position.X + workspace.CarTwo.VehicleSeat.Position.Z)
local Distance = (Car2Pos - Car1Pos).magnitude
print(Distance)

By only getting the X & Z planes, you’ll remove the elevation factor. You would however want to keep elevation as a factor if you have a track that crosses over itself like with a bridge or a tunnel, because if the two drivers cross that section at the same time, it’d be the same as being right next to each other on a flat part of the track.

If you’d really like to know how I do my checkpoints, I’ll send how I do it your way. My ovals personally use 4 checkpoints, but if you want to keep the complaints down about “I passed someone and it didn’t show it until a half a lap later” you can just have more checkpoints to update sooner.
Here’s an example for a fairly complex course.


I placed checkpoints at the start and finish of every corner because corners are the most likely sites of passes, and I cut some of the longer straights into sections in case there is a crash or random passing on the straights.

You could use checkpoints to determine who’s in front for cat & mouse though, and use the distance formula to calculate distance between them for displaying back to the drivers, and checkpoints are extremely useful to calculating whether a driver is driving the course in the correct direction or not, so you should definitely consider at least some form of using checkpoints for safety measures. Also, using checkpoints can help defeat people being able to teleport to the mouse’s location for the easy win.

Without checkpoints, it’s very hard to determine who is “in front” because you have no reference to the track really.

4 Likes

Ah thanks for the help. I’ll probably end up doing something like this except instead of parts use regions (because .touched event seems unreliable) but yea we’re gonna be having lots of hairpins so there’s a lot of good information here.

This is the top of one of our tracks (still being developed) but since this would call for a ridiculous amount of checkpoints do you think it would make more sense just to apply the Distance algorithm ( on X,Z Axis ) to the checkpoints? The downside would be that it makes the checkpoints effectively cylinders but it would work better than touched and be simpler than regions (my other dev doesn’t know much about scripting and all so I would have to do all the checkpoint placing if we chose regions.)

1 Like

So, personally if i was working on this track, I’d say if you use checkpoints that are straight blocks versus using checkpoints that are cylinders, this would be a setup I’d go for:

I’m not sure what you’re suggestion with:

So I can’t be much help there. Ultimately checkpoints are a lot of work, and all, but it’s one of the easiest ways, and like I said in the other post you made, touched inside the character’s torso is pretty darn reliable. That being said, I’ve used the less reliable, touched inside of vehicleseats for all of my games, and got away fine with 10 players on maps.

I have 0 experience with Region3 so I’m not much help there, sorry.

1 Like

If you make the checkpoints as flat planes, or lines across the track, you can get the accurate distance from any checkpoint as well as the side of the checkpoint a point is on with a dot product:

local checkpointPart = script.Parent
local surfaceNormal = -checkpointPart.CFrame.lookVector --assuming the checkpoint part back is facing towards the "start", and front is facing towards the "finish"
local planePoint = checkpointPart.Position

function GetDistance(surfaceNormal, planePoint, point)
	return surfaceNormal:Dot(point) - surfaceNormal:Dot(planePoint)
end

A positive return value number would mean that a point is past the checkpoint while a negative number would mean that a point is before it. The larger the number, the farther ahead a point is. You can advance players to the next checkpoint as soon as you see that the number is positive.

This approach gives a number that isn’t skewed based on where the checkpoint is on the track like if it was a sphere or a cylinder, but it would require that you put enough checkpoints to ensure that players can never be on the “front” side of the checkpoint if they haven’t actually reached it yet. It is also more stable because there is no way to get past the checkpoints without the check detecting it. It gives absolute distance to a full plane, rather than just a point.

You would also need to be careful about branching paths so that you avoid sending the player down the wrong branch on accident because they hit the other branch’s invisible plane. That issue could be solved with bounds checks like planes on the sides of the roads facing inwards so you need to have a positive value on all of planes being checked at once to be considered past the checkpoint.

1 Like

This dot function seems very useful, but wouldn’t that become problematic in this situation:

since the player can go backwards and they’ll be in front of the second checkpoint?

If you limit checkpoint progression to be based on the last checkpoint you hit and put a checkpoint in the middle of that back straight, then it shouldn’t be an issue. If you’re worried about it becoming an issue, you can form a bounding shape around the track with planes and require all plane tests to pass to advance while only using one to measure distance along the track.

You can model some pretty interesting bounding shapes using this kind of detection:

Each face here would be a plane pointing inwards. A point would need to be on the “front” side of all faces to be considered inside.

These checkpoints don’t always have to be visible to the player, so you could place more than advertised if you don’t want the track to become visually cluttered by them.

2 Likes

I would try to make it so when the car is driving forward, it adds to a value in the workspace. When a car is driving backward, it subtracts a value in the workspace. Player with the highest value would be in front.

What defines driving forward and backward? If you mean relative to the direction of the track, then this poses its own problems. You would constantly have to check with the track and find out what “forward” is.

Theoretically, you would be able to drive a very tight zigzag up a straight part of the track, and it would rack up more “points” than just driving straight along the track, since it is driving forward with the track for a lot longer.

A checkpoint system would be a lot easier to make and likely sufficient rather than trying to determine what is “straight” relative to the car frequently. This probably wouldn’t work well on curved track segments with a lot of parts, or just one curved mesh part, which wouldn’t give the right direction anyway.

1 Like

Um… for a Cat & Mouse situation; don’t you already know who is in front? Just saying…

Prosperous New Year,
Brian

I posted this on another thread (Here) but I think I’ll end up doing this:

  • I’ll convert the “part” checkpoints to Region3’s (in a script so my partner doesn’t need to do the math)
  • Client checks if vehicleSeat is within Region3
  • If they are, it fires the server with tick() as an argument
  • Server will verify region3 when fired
  • if the checkpoint is the start/finish line, it’ll check the tick() of each car that crossed the line and sort the racers based on time.

The only problem would be that the tick() could be manipulated by a hacker who figured out that number defines the final pos… I could just use tick() on the server, but that would work just as well as using the order the events were fired. I don’t know if there’s a way to get around network lag ( other than casting a ray across the finish line when a player comes close to it, and using it to detect the first bumper to cross ) but yea any ideas here?

1 Like

TO this day im still trying to do this. How do you do this with checkpoints?

2 WHOLE YEARS, PLEASE HELP ME LOL

How would I go about using the checkpoints to determine positions?

Should I use values in the player every time they touch a checkpoint (with an anti cheat system that would make it so touching the same checkpoint would take 30 seconds), OR finding the distance?

Honestly im leaning towards numValues because I could use the checkpoints in a different situation. And is just simpler for me.