I built a spaceship controller using mouse control and noticed something odd - when i move the mouse in a circular pattern the Z axis of the ship rotates. So basically if you start looking at an upright space station and use the mouse to rotate the ship on angles enough (or in a circle) you can watch the space station go upside down because your ship has rotated on the Z axis.
I found a “fix” for this doing the unthinkable - modifying a Quaternion z component directly. This solves the z axis rotation (roll) problem and mostly works, rotations straight up or down all work fine. However, moving the mouse to rotate, say, in the NE corner of the screen then switching to NW causes some unexpected rotations. I know this is due to my Quaternion manipulations and after hours of GPT/Gemini I’m just going in circles now and could use some help.
Here is the source code below, if i comment out the .z = 0f portion then the problems go away but it rotates on the Z. If i leave in the .z = 0f portion then no rotation on Z (good!) but direction changes on angles cause wonkiness. Also note, if i return the mouse to center and try again on an angle it works again - so i think its some cumulative error - hopefully a Quaternion guru exists out there?
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class SpaceController : MonoBehaviour
{
public float DeadZone = 0.1f;
public float RotationSpeed = 100f;
private Rigidbody rb;
public Vector2 mouseDelta = Vector2.zero;
private float halfScreenWidth, halfScreenHeight;
void Awake()
{
rb = GetComponent<Rigidbody>();
halfScreenWidth = Screen.width / 2f;
halfScreenHeight = Screen.height / 2f;
}
void Update()
{
// Calculate the mouse input position from center
float x = Input.mousePosition.x - halfScreenWidth;
float xNormalized = Mathf.Clamp(x / halfScreenWidth, -1f, 1f);
float y = Input.mousePosition.y - halfScreenHeight;
float yNormalized = Mathf.Clamp(y / halfScreenHeight, -1f, 1f);
mouseDelta = new Vector2(xNormalized, yNormalized);
}
void FixedUpdate()
{
HandleMouseRotation();
}
private void HandleMouseRotation( ) {
if (mouseDelta.magnitude > DeadZone)
{
// Calculate yaw based on horizontal component projected onto XZ plane
Vector3 mouseDeltaXZ = Vector3.ProjectOnPlane(mouseDelta, Vector3.up);
float yaw = mouseDeltaXZ.x * RotationSpeed * Time.deltaTime;
float pitch = -mouseDelta.y * RotationSpeed * Time.deltaTime;
// Combine yaw and pitch rotations into a single Quaternion
Quaternion combinedRotation = Quaternion.Euler( pitch, yaw, 0f );
Quaternion newRotation = rb.transform.localRotation * combinedRotation;
newRotation.z = 0f;
newRotation = newRotation.normalized;
// Apply the combined rotation using local rotation
rb.MoveRotation( newRotation );
}
}
}
It’s impossible to provide a relative two axis rotation input without affecting the third axis when the mouse input should be relative to the ship. In space there’s actually no up or down. So when you really want free movement in 3d space, you need input for the 3rd axis.
I played a log Space Engineers and you control your roll with Q and E when you enable your jetpack. However without the jetpack, when you are inside a gravity well, your character automatically orients itself up right in relation to gravity and you get the usual absolute FPS controls. So the mouse x delta changes the y rotation of the character itself (around the axis of gravity) while the mouse y delta is used in an absolute ±90° up down movement for the camera only. The camera is of course part of the actual player.
So you should ask yourself what kind of movement do you want to allow, because moving the mouse in circles is exactly the kind of thing that makes you roll slightly, depending on how “large” your circles are. The typical example that shows this is: Look forward, aligned with world forward. Now look up 90°, look left 90° look down 90°. You’re back to your forward direction, but your view is rotated counter clockwise by 90°. So this is completely normal and can’t be mitigated when using relative motion. You would need to move absolute to a certain reference frame.
Though as I said, actual 3d freedom means you HAVE to control the roll as well. You can not just use two free rotations. Actual free 3d movement works perfectly as it is and is consistent with reality. So you generally rotate around your own up and right vectors in space, disconnected from any reference frame. You just need to control the roll yourself in that case. There’s not really a way around that unless you do introduce some kind of constaint to a particular reference frame.
I never played space commander, however from that video we can tell that they did not actually use free movement but a constraint movement and always kept the same world axis up. You could tilt slightly sideways but it always tilts back to keep the roll aligned with world up. This would be a classical FPS controller. In the video you showed he never flew straight up or down which would probably be an angle of singularity.
Many games did this but it doesn’t really offer proper free 3d space. It’s essentially a 2d map. Battlestar galactica online did this as well like many others. It’s often called the Star Trek phenomenon where everyone seems to agree where “up” is in space ^^. When ships meet in open space they always meet them aligned which wouldn’t make any sense in actual space.
That’s why I mentioned SpaceEngineers which has actual 3d free look, at least when outside a gravity well. When inside a gravity well and don’t use your jetpack you get the usual FPS controller which limits your up / down angle to ±90° and always aligns you with gravity.
If you really want something like that space commander, it’s literally just the usual FPS controller, just in space. The tilt of the ship is completely artificial on top of your actual camera movement and just temporary. It just indicates the rate of yaw. You never actually roll. The camera never rolls at all, just the ship banks temporarily and always returns back to “neutral”. So the game takes place in a certain plane and you just can go up and down a bit.
That makes sense, so to provide a bit more context.
I want mouse to control pitch/yaw only. Q/E keys will allow player to roll.
I know this is something that has been done as playing games like Space Commander, etc… do this, so in essence this is the style of control i would like here:
I know they must solve this somehow, or maybe they handle it differently I don’t know, certainly not with a Clamp on pitch to avoid Gimbal Lock either. So how this looks and feels is what i’m after, using my other controller (this is a fresh attempt) it feels ok but this changing z rotation while mousing to go on angles just doesn’t feel right to me - something is off. Appreciate the quick response and assistance !
You know I just installed Everspace 2 again (that’s the feel i wanted) and I’ll be darned if it doesn’t rotate on the Z as well … why have i never noticed this before? It seems less aggressive than my controller but still - anyhow thoughts still welcome.