Rail Platformer Collision Detection

I’m interested in making a really dynamic and flexible platformer on rails. The world is 3D, but the player is constrained to a 2D rail that curves around the 3D environment, with movement constrained to the usual XY along that rail. (For an example of what I mean, see Tomba 2 or this part of Klonoa.)

I’ve already developed a “rail system”. Basically, it connects a number of nodes together into one long spline, and objects can “connect” themselves to the rail to move along it. Their X progress along the rail is defined by an interpolation value ranging from 0.0 (the first node) to 1.0 (the next node). Traditional Y space movement is defined using continuous normals defined at each node.

The issue is collision detection. It would be nice if I could use CharacterController.Move() to do all that jazz for me, but it assumes my movement is defined by directional vectors (which, to be fair, is true for 99% of applications). If I use Move(), it would only calculate movement in a straight direction tangent to the rail; however, the rail can twist and curve, so movement has to also be along the curve (defined as a value between 0.0 and 1.0).

As a visual aid, consider the following image (borrowed from Google…):

Spline Graph

The spline represents a top-down view of how I might have the 2D rail weave through a 3D environment, with nodes at t=t0, t=t1, etc. CharacterController.Move() requires a Vector3 to be passed to it that represents a straight, directional movement of a CharacterController object. However, the best I can pass to it on my rail system is a Vector3 tangent to the spline at that point, as can be seen by tng0, tng1, etc. Obviously, these tangent values don’t represent an object’s actual movement along the rail and could result in a false collision if a collider exists just off the rail, or a missed collision if a collider exists on the rail and the tangent misses it. (Not to mention that the returned Vector3 resulting position would be inaccurate and off the rail.)

Is there a good solution for this? I’m thinking it’s going to have to involve me doing collision detection and, upon detecting a collision, move a game object backwards along the rail and its Y velocity until it no longer detects a collision. These “rewinds” will have to be of a specific step size, with a larger step being less resource intensive and a smaller step being more accurate.

Another visual example of the problem:

Rail Example

Sound about right? Any advice?

So yea every curve is really a series of straight lines. All you need to do is ensure that the steps are small enough you don’t ever go off the rails.

I think by creating a list of waypoints and simply iterating through the list you can get directions easier and safer and fix any issues quickly with some map editing.

whenever you reach a waypoint that is considered your location for the purposes of choosing your next movement vector.

for example you pass the third waypoint and would like to go on to the next one so your position is called waypoint 3.
if you press to go back you would move towards waypoint 3.

if you press to go forward you move towards waypoint 4.

you said this is a unique problem but really the rails problem is seen in any racing game.
your racing along a narrow 3D path. It’s been solved many times normally through pathfinding, and with racing that is often waypoint based.

You may wish to check out the roads/path tool in the asset store. it’s free.
There are several paid ones as well.

Best of luck.