Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I was wondering how collisions in some simple 3d car racing games are done (especially in games like Outrun 2/Motoracer).

In classic car racing games with complex environment (open world), I guess this is done with a basic box (for the car) to plane collision (for track, buildings an other stuff). The whole thing would be optimized using some bounding boxes (this is the way collision is done in many games).

In a game like Outrun 2/Motoracer, the gameplay is so simple that developers maybe dont need that and everything could have been simplified a lot. For those who never play it, here is what is so specific :

  • The car/bike is always glued on the road.
  • The road is always same size and have a very simple shape.
  • The only possibilities is to follow that road, its not possible to leave the road, or to get in collision with something else (except other cars/bikes but we don't care).
  • When you collide with the road, very basic arcade collision is done (the car is simply pushed away from it)

Here is how i think collision (could) have been done :

The whole track could be considered as giant a 3d bezier curve. From that curve, the road polygons could be generated (using front, left and up vectors generated from curve). Other elements (like houses, trees, ...) could be also placed and aligned using this method.

Then, to handle the collisions (and draw car) :

1) Find closest position on 3d curve from current car 3d position. In other words, transform 3d car position to bezier curve position. Every 3d position on the road could be considered as a displacement along 3d curve (t) + lateral displacement (d). Check image below if it is not clear (this is a 2d example but this apply to 3d easily).

enter image description here

when t = 0 car is at beginning of track section, when t = 1 car is at the end. when d = -1 or 1 car is at border of track, when d = 0 car is in the middle of the road

2) align the car to the road using t and d (very simple : for any t and d values i can get a 3d position + up/front/left vectors). the car is now glued on the road

3) check lateral displacement d of car. if value is too big (d > 1) or to low (d < -1) car is away of track. just clip it to put car in correct place.

This also make 3d culling very simple, just draw the track from current car t position to t + some_big_enough_value_to_avoid_visible_clipping.

Or maybe i'm completly wrong : it would have been lot faster and simpler to just check collision of the car (a bounding box) and a very simplified set of polygons that represent the track (without the buildings and such). The 3d world (and the resulting colision model) would have simply been generated before, using some 3rd party tool (no more 3d curve when running the game, just a bunch of polygons).

share|improve this question

1 Answer 1

up vote 13 down vote accepted

I have worked on a few commercial games similar to those you describe.

In each of those games, we actually had polygons creating an invisible "wall" along the sides of the track, and did traditional collision testing against those walls. This meant that we could have some additional collidable hazards at the side of the road, inside of the invisible walls, and also let us vary the road width faster than you normally can with a spline approach.

But with that said, we also did what you list in the how I think collision would work section in order to guard against collision tunnelling/glitches, and this system was also heavily used for racing AI logic. We also used it for determining which cars were in the lead, so that we could display a "1st/2nd/3rd/etc" indicator on the HUD. Sometimes this data was also used for respawning a car after a major crash.

One piece you missed in how I think collision would work is that when you're working with splines like this, you'll normally give the splines ribs. Ribs are bits of data expressing how far the track extends sideways in each direction from the spline. So for a spline that's 100 meters long, you might have 50 ribs, giving the track width every two meters along its length. This allows your track to change widths along its extent. In the games I've worked on, these ribs have also distinguished between "track surface" and "drivable area". So you'd have one set of road widths telling how far from the middle of the spline you have nice tarmac, and then another width saying how far the sand/grass/whatever goes outside of that. That let us have players able to drive a reasonable distance off the track, but still have AI know where the real road surface was.

Many games I've worked on have also stored other data in the ribs; one game baked track lighting information into the ribs, for easily calculating whether or not an area was in shadow (which was then used for car rendering, deciding whether or not to draw a lens flare, and other effects). Another baked in information about which cinematic camera placements could see that part of the spline, so we didn't have to do line-of-sight calculations during replays. Still another included information about how many lanes were on the spline, which direction they went, and the horizontal displacement where each lane was located. This allowed us to include traffic cars which could correctly drive within road lanes. Ribs are fantastic for storing any sort of varying data you might need about your road surface.

Ribs are typically stored in an array that's associated with the spline. For speed reasons, a normal implementation will have evenly spaced ribs, so once you know an object's distance along the spline, you can calculate the nearest rib index in the array by dividing the distance along the spline by the distance between ribs. Otherwise you're stuck doing binary searches through your rib array to find the correct road width data.

Your culling description gives a good basic description of how the spline approach can be used, but it's actually a bit more complicated than you suggest -- if you use splines for culling in this way, long hairpin turns often won't draw the opposite side of the turn, since when measured by the distance along the track, the opposite side of the turn can be very far away, even if it's only a few meters away when measured as the crow flies. Additionally, the distances at which world geometry can be seen is typically different than that at which track mesh can be seen, so those don't really fit into this system either. My experience is that in most cases, it's better not to rely on track-following logic for determining whether a model should be drawn; it's much more reliable and causes fewer glitches to use standard camera frustum testing for that.

share|improve this answer
2  
+1 for nice answer and ribs, awesome! –  Gustavo Maciel Mar 10 '12 at 4:04
    
Informative and fun to read answer –  onedayitwillmake Mar 12 '12 at 2:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.