Saturday, 2 November 2013

Car tracks

After tracks, the next step is obviously to have some cars on them, carrying paying guests of course!
In the real world, you just put the car on the track, and it will follow them. In the digital world of make-believe, car graphics don't care about track graphics, and you have to explicitly tell them how to move through the world.

If you remember the original Rollercoaster Tycoon programs, you'll know tracks came in all kinds of bendy shapes, so how to do that?

One answer that should work (we think), is segmented cubic bezier splines. Basically, you define a start and end point in 3D space, and two intermediate control points (also in 3D), and the bezier algorithm computes a smooth line from the start to the end point. For the more bendy shapes, one such spline is not sufficient, you either need a higher order bezier curve (but it's math becomes complicated), or you chain a number of cubic splines after each other. If you do that careful, the cross-over from the end of one spline to the start of the next spline is also smooth.

So far so good, bezier splines gives a line of rope through 3D space for the car to follow. But what about the orientation of the car? (Keep in mind, the car ignores the track graphics!)

Just a line doesn't tell whether the car is up-right or upside-down (or anything in-between). To solve this problem, a track also needs a roll orientation for every point at the line. A smooth path from a starting roll value to an ending roll value (in degrees).... Another segmented cubic bezier spline to express the roll orientation in degrees!

From the direction of the 3D line (for the mathematically inclined, its derivative) and the roll, the pitch and yaw can be computed (hopefully, I haven't actually tried that yet).

For the test rollercoaster track graphics, roll is simply 0 (upright orientation), so that's easy. The path involved a bit more experimenting. I made a small Python program that plotted the path curve onto the existing track graphics, and tuned the start, end, and control points until it all looked ok. You can see the result above.

For example, the path of the level-to-going-down-track in negative x direction (bottom-right sprite) is defined  as

car_xpos: splines { cubic { a: 255; b: 150; c: 100; d: 0;   length: 1000; } }car_ypos: splines { cubic { a: 128; b: 128; c: 128; d: 128; length: 1000; } }
car_zpos: splines { cubic { a: 80;  b: 78;  c:  50; d: 15;  length: 1000; } }
car_roll: 0;

The roll is 0, as expected. The x position runs from 255 (point a) to 0 (point d), with intermediate control points at 150 and 100. The y position is 128 all the time. The z position starts at 80, and ends at 15 (points a and d). Point b at 78 is almost the same height as point a, so near the start the path is almost level. Point c is much higher than point d, so it goes down more steeply.

So far, it all looks good, but getting to the point of a car following the track on the screen will be quite some work. Then we will see whether the above math actually works :)