Paper Breakdown of Grind Logic
In the roller parkour adventure Radio Noize grinding is a base core mechanic. This post will be a reflection on how I presently have gone about placing and instantiating rails and rail components, and how Faye goes about engaging these rails to give the illusion of a rail grind. Please note that the more in depth explanations will be as they pertain to Unity 5.
The first key word of focus in this process is instantiate. This is to say that the rails themselves are in fact instantiated. The grind rails in Radio Noize are heavily dependent on Bezier Splines. For those who aren't familiar, beziers are sets of coordinates that make up a curved line. Rather than go about explaining the process of using beziers in Unity, I would point you in the direction of Catlike Coding, who has an in depth explanation of lines and beziers here :
You'll notice that Catlike Coding's tutorial already covers the notion of a Spline-Walker, which allows the moving of an object along a spline over a duration. If your player or object stays constantly affixed to the bezier, then this is already fine, and you're set. However, Faye needs the ability to engage and dissengage the rail at point of contact. The spline walker method however, complicates this, as the position along the rail is set on finding the point on the spline she would be at at a certain time with the understanding that the duration of time it takes to complete the rail is set. The tutorial also however includes the idea of a Spline Decorator. This opens many doors for points of interaction.
Theoretically, this allows for the dynamic creation of rails using kits - one could create a series of pipe-like objects to render the rails themselves.
More importantly, this instantiation of objects (which we will reffer to as rail components) provides ordered segments of rail that each have their own position. The position serves to be the most important component of these rail components. If one were to model rails and other grindable surfaces outside of Unity, then he/she could instantiate empty game objects, or at least renderless objects and then trace the surfaces using splines.
Once we have these transforms (and thus positions) we can have our player lerp (interpolate from A - B) to each component's position. To help correct height above rail, one could also add a Y offset to the target position before starting her lerp. I would suggest even making the offset public so yuu or your artsist/level designer can play with this value without needing to consult the programmer.
At this point we know how to make our player lerp from position to position, but not how to know where she lerp to, or when to start lerping. The method I used solve both of these problems required attaching a script to my rail components. At the point of instantiation, I tell the component which rail it is on (incremented value at each bezier), and what component came before, or after it (if applicable), and I set booleans for head or tail of a rail.
On a standard rail, if the component is checked as "head" it will not have a last, and if "tail" it will not have a next. If the rail loops, then the next position for the tail will be the head of the same rail, and the last position of the tail will be the head.
With an order now set for our players lerps, we need a way to know how and when to start. Within the Rail Components there is a boolean for "grindable." The Rail Components also have a trigger collider. If the player enters the trigger area, then the component is grindable.
Now, in the player will need reference to the Rail Components in the scene within an array. If your player is in a state that they can enter a grind, then run a function that checks for a grindable surface. If one is found, set it to the target position, and start your lerp.
Now we have the basis of rail engagement, we need to determine rail bias - We need to know if your going one way along a rail or the other. I had tried several different methods for determining bias, and in the end the most apparent solution was best, I just didn't know how to word it. Essentially, at the point of engagement, you need to compare your players heading angle with the heading angle of the rail component (note each of your rail components conveniently faces the next component by default). if the difference (the aboslute value of segmentHeadingAngle - playerHeadingAngle) between these angles is <= 90 (your player is between facing the same direction and being directly perpendicular to your rail component) then they will go forward, or they will continually lerp to the current component's "next." If the difference is >90, then they will lerp to each component's "last."
If there is no position to move to, or the player jumps, she will exit the grind state.