Quaternion and gravity trouble

Hi folks,

I’m trying to do a custom gravity setup to work with characters moving on small planets. Unfortunately I have some trouble with how the transform moves when it’s close to 100% downwards (0,-1,0).

Around that spot, the character starts to turn in circle really quickly.
But when I cross it straightly coming forward from the top I have no problem going through it.

Probably a misunderstanding of quaternions… but I’ve been doodling around for a while now!. A fresh look would help and be super appreciated :wink:

Cheers,

Vincent

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GravityPlayerController : MonoBehaviour {

    // Movement
    private Rigidbody   myBody;
    private Transform   myTransform;
    private Vector3     moveDirection;
    private Vector3     gravityUp;
    private Vector3     worldUp = new Vector3(0, 1, 0);
    public float        moveSpeed = 1f;
    public float        gravityForce;
    public GravitySource gravitySource;
    
    // Inputs
    private float       moveFrontBack, moveLeftRight;
    private float       mouseX, mouseY;
    public float        mouseSensitivity = 10f;
    public Text         debugText;

    // Other objects
    public GameObject target;


    void Start()
    {
        myTransform  = transform;
        myBody       = GetComponent<Rigidbody>();
        gravityForce = gravitySource.gravityForce;
}

    void Update()
    {
        mouseX          += Input.GetAxis("Mouse X"); 
        gravityUp       = (myTransform.position - gravitySource.transform.position).normalized;
        moveDirection.Set(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

        Debugging();
    }

    void FixedUpdate()
    {
        myBody.MovePosition(myTransform.position 
                            + myTransform.TransformDirection(moveDirection) 
                            * moveSpeed);

        myBody.MoveRotation(Quaternion.FromToRotation(worldUp, gravityUp) 
                            * Quaternion.Euler(0, mouseX, 0));

        myBody.AddForce(gravityUp * gravityForce);
    }

    void Debugging()
    {
        debugText.text = "Rotation = " + myTransform.rotation.ToString("F6") + "

"
+ "Position = " + myTransform.position.ToString(“F6”);
}
}

public class GravitySource : MonoBehaviour {

    public float gravityForce = -9.8f;

}

myBody.MoveRotation(Quaternion.FromToRotation(worldUp, gravityUp) * Quaternion.Euler(0, mouseX, 0));

this

Quaternion.Euler(0, mouseX, 0));

part will cause that kind of problems most of the times, and it’s so hard to wrap it your head around.

once i had same issue, and i solve it by saving last “mouseX” position from previous frame, and check if its changed.
if its not changed at all , dont use it at all, if its changed lite bit you are okay, if its change rate is huge, just lerp it, dont try to change that rotation all at once in one frame.

i hope this will help.

Hi folks,

I’ve been screwing my head off trying to get deeper into the magic of quaternions and finally deduced that the less you play directly with quaternions, the better.

Looking at this video on YouTube, I realized that, as a newcomer to Unity and game dev, I’d be better off using functions generating and manipulating quaternions, rather than trying to steal the wizard’s hat to enchant brooms.

In the end this code worked out perfectly.

Cheers, and thanks for your replies!

    void Start()
    {
        myTransform = transform;
        myBody = GetComponent<Rigidbody>();
        gravityForce = gravitySource.gravityForce;
        myBody.useGravity = false;
        myBody.constraints = RigidbodyConstraints.FreezeRotation;
    }

    void FixedUpdate()
    {
		// Movement
        moveDirection.Set(Input.GetAxisRaw("Horizontal"), 
						  0, 
						  Input.GetAxisRaw("Vertical"));
						  
        moveAmountTarget = moveDirection.normalized * moveSpeed;
        
		moveAmount = Vector3.SmoothDamp(moveAmount,
										moveAmountTarget, 
										ref smoothMoveVelocity, 
										.15f);
        
		myBody.MovePosition(myBody.position + myTransform.TransformDirection(moveAmount));
		
		// Gravity rotation
        gravityVector = (myTransform.position - gravitySource.transform.position).normalized;
		
		myTransform.Rotate(Vector3.up * Input.GetAxis("Mouse X"));
        
		myTransform.rotation = Quaternion.FromToRotation(myTransform.up, gravityVector) 
							   * myTransform.rotation;
		
		// Apply gravity
        myBody.AddForce(gravityVector * gravityForce);
    }