The trade for smooth trains
Inglenook VR was a group project for Interaction 2: Virtuality and Cognitive Modelling, studying collaborative learning in VR and built around a shunting puzzle: eight numbered carts, three sidings, get them into order in as few moves as you can. Almost all of the build time went into two mechanics: coupling carts together, and moving them along track.
The track is splines. A spline is a path defined by control points you place by
hand, which makes it a good fit for something that curves but is not allowed to
wander. The useful part is GetNearestPoint: take the ray from the hand or
controller, find where it is pointing, and snap to the nearest point on the
spline. Grabbing a cart never moves it freely. It moves it along the rail. We
hold that every tick, teleporting each cart to the nearest point on its spline,
and that is what makes it read as a train rather than a box you are carrying.
Coupling is OnTriggerEnter. When two colliders meet, we create a hinge joint
between them and store a reference to the cart behind on the cart in front.
That gives the whole chain for free, since checking whether the puzzle is solved is
just walking the stored references and comparing the order against the target.
Decoupling leans on something specific to VR: grabbing an object overrides physics, so the hand always wins against the joint. That means we can break the hinge once two carts are separated by more than a threshold distance, and clear the stored reference at the same time. Pull two carts apart and they uncouple, which is exactly the gesture anyone would try first.
Both of those decisions bought us genuinely smooth movement, and they also work against each other. The physics override is what makes decoupling feel right, and it is the same property that lets a hand drag a cart clear of its rail. Once it is clear, a position re-derived every frame from the nearest spline point can find that the nearest point belongs to a different siding, and the cart snaps across. In a yard where three tracks run alongside each other, that is not a rare event.
The splines were early work, and the implementation itself worked. What we never went back and dealt with was the case where physics gets ignored completely, and by the time that mattered the foundation was too settled to change cheaply. The lesson I took from it is the boring one: build from the ground up, and test the pieces against each other early, while a better implementation still costs you nothing, something I have applied in every project since.