Hello, I’ve been wanting to prototype some FPS mechanics for a while, so I decided to give Unity a shot. At the most basic, I want the player to operate in a zero-gravity environment but keep the controls feeling very simple and traditional otherwise.
Put simply, the player essentially has magnet boots and otherwise moves along any flat “ground” surface as they would in a regular FPS game. Implementing the basics of this movement behavior started off surprisingly well. The player generally transitions to new surface orientations smoothly, and mouselook works in all orientations (no sudden camera flipping).
My only real issue with the feel of this system is, the direction of the player’s aim moves along with the rotation of the body. This can mean the aim suddenly jumps quite a bit, and if at all possible, it seems preferable to keep the player looking at the same direction even when rotation of the camera and the body changes (within limits, like only being able to look +/-90 degrees up or down).
Over the past week or so I’ve tried to implement this in multiple different ways but I am continually falling short.
With varying combinations of vectors, quaternions, and Euler angles I’ve generally been following this process:
-
Record the desired look direction before any body rotation (or keep it independent of body rotation, i.e. not a child of the body).
-
Rotate the player’s body without concern for look direction
-
Rotate the player’s body again such that it remains on the same up/down axis (usually transform.up), and also minimizes the angle between its forward direction (transform.forward) and the desired look direction. This seems to be the hardest step.
-
Rotate the look direction back to the original look direction (parent/child relationship) OR align the position of the camera back to the correct spot on the player’s body, if needed.
-
Re-constrain or “fix” up/down look (+/-90 degrees, as mentioned above). This can also been tricky.
I’ve seemingly gotten very close with 4-5 separate implementations of this, but they all seem to drift or otherwise not work as expected. I also assume a more knowledgeable person could probably come up with a more elegant solution.
The most important piece I can provide up front is probably my method of rotating the player’s body to a new surface smoothly. It’s not finalized, but it seems to work well.
if (Physics.SphereCast(transform.position, 0.45f, -transform.up, out magHit, playerHeight / 2, groundMask))
{
rb.MoveRotation(Quaternion.Slerp(rb.rotation, Quaternion.FromToRotation(transform.up, magHit.normal) * rb.rotation, 0.05f));
}
Thanks for any guidance in advance.