For GAM 392 at DePaul, I’m working on a team to make a physics-y racing game where you play as a marble in the Unity Game Engine. I had been working mainly on camera behavior and character controls. We had tried a few control schemes at the beginning and decided to implement controls where W when forward, S hit the brakes and A and D strafed left and right respectively. After we showed off our vertical slice to the professor, Ryan Wiemeyer, he reccomended changing the controls to something more like what we call “tank controls” where A and D turn the character instead of strafing. I had to scrap a lot of my work so I thought I would do a brief writeup about it.
The main problem with implementing strafing controls in the game was that “forward” could really be in any direction depending on where you were on the track which has turns and drops and jumps. Strafing is always perpendicular to this forward direction and the camera was position behind the character in the negative forward direction so it was imporant to figure out a way to find it. Forward could not be found from world axes because it needed to change when the player went around crazy turns and things. It also could not be found from the character’s transformations because the marble model is constantly rolling so its rotation transformation was unpredictable.
Logically, the forward direction depends on what type of piece you are currently on so I designed and implemented a system where once the character collided with a piece, that piece was saved and the method to find forward changed.
Straight pieces were the easiest. Forward simply depended on the piece’s rotation in space. If the piece were rotated 45 degrees down in Z, then the forward direction would be 45 degrees down in Z. The forward direction was set to the piece’s local Z axis.
The more challenging pieces were the curved pieces. The forward direction had to change as the character rolled through it. All the curved pieces we had developed so far were 90 degree circular turns so I was able to handle them all similarly. I set the forward direction to a value that was spherically interpolated from the incoming direction to the outgoing direction. The incoming direction was always the local Z axis of the piece. All the models were built this way. The outgoing direction was determined by the type of piece. For example, if it were a turn to the right, I multiplied the local Z by a Quaternion that was set to Quaternion.FromToRotation(Vector3.forward, Vector3.right). This got me the two end points for the interpolation.
I’ll be referring to the third argument to the slerp function (static Vector3 Slerp(Vector3 from, Vector3 to, float t)) as the interpolation paramenter. For the interpolation parameter, I had to determine how far along the curved piece the character was. I got a vector from the character’s position to the origin of the piece, which by design was always at the entry point of the model. Then I got the component of this vector that was parallel to the piece’s local Z axis. This magntude of this vector measured the distance that the character had travelled into the piece in the forward direction. I scaled it to the piece’s scale in Z in case we ever wanted to change the size of the piece. The magnitude was then multiplied by a magic constant value that was empirically determined by measuring the physical distance from the starting position to the exiting position of the curve in the Z direction in the Unity scene editor.
This all had the effect that when the character had just entered the curve, the interpolation parameter was 0 and the forward direction was the piece’s local Z axis. When the character was just leaving the curve, the interpolation paramter was 1 and the forward direction was the piece’s outgoing direction. In between, it was spherically interpolated based on the “depth” in the local Z direction that the character had gone into the curve.
This method worked for left turns, right turns, up turns and down turns which were all 90 degree circular turns. I could have extended it to work for any circular arc by changing the outgoing angle. We had planned to do any very complicated marble track pieces like loops or funnel pieces in a completely different camera style.