How to player look in direction of movement but always have the transform's up vector look at the

How to player look in direction of movement but have the transform’s up vector point in the direction of gravity?
I want to make a game that utilizes physics like Super Mario Galaxy where the player can run on irregular shaped objects which game engines don’t have.

I used this script to control gravity and also control the player but the problem is my character can move on any object but still doesn’t point in the direction of movement.
I can’t get a clear understanding of interpolation so I don’t know what to do?
This is the whole script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class PlayerControl : MonoBehaviour
{
    public GameObject teleportDestination;
    public GameObject orbit;
    public Rigidbody Rb;
    public int life = 3;
    public bool canJump = false;
    public bool jump = false;
    public float MovementSpeed = 2f;
    public bool ApplyGravity = true;
    public bool ApplyParallelGravity = false;
    public bool IsMoving = false;
    public bool shouldFall = false;
    public bool isGrounded = true;
    public float distanceToGround;
    public Vector3 Groundnormal;
    public Camera camera;
    public bool cameraControl = false;
    public int moveX;
    public int moveZ;
    public Vector3 _direction;
    public Quaternion newRotation;
    public Vector3 gravityUp;
    public Vector3 dir;
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    public void Update()
    {
        camera = gameObject.GetComponentInChildren<Camera>();
        Application.targetFrameRate = 100;
        print(life);
        if (life == 0)
        {
            Thread.Sleep(3);
            StartCoroutine(RespawnWait());
        }
        if (life < 0)
        {
            Thread.Sleep(3);
            StartCoroutine(RespawnWait());
        }
        if (life > 0)
        {
            if (shouldFall == true)
            {
                Rb.velocity = -transform.up;
            }
            RaycastHit hit = new RaycastHit();
            if (Physics.Raycast(transform.position, -transform.up, out hit, 10))
            {
                distanceToGround = hit.distance;
                Groundnormal = hit.normal;
                if (distanceToGround == 0.2f)
                {
                    isGrounded = true;
                }
                else
                {
                    isGrounded = false;
                }
            }
            if (gameObject)
            {
                if (ApplyGravity == true)
                {
                    gravityUp = (gameObject.transform.position - new Vector3(651, 46, 476));
                    Vector3 bodyUp = transform.up;
                    newRotation = Quaternion.FromToRotation(bodyUp, gravityUp) * transform.rotation;
                    transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, 50 * Time.deltaTime);
                    Thread.Sleep(1);
                    Rb.velocity += ((-gravityUp * 10) * Rb.mass);
                }
                if (ApplyParallelGravity == true)
                {
                    ApplyGravity = false;
                    gravityUp = orbit.transform.up * 10;
                    Vector3 bodyUp = transform.up;
                    newRotation = Quaternion.FromToRotation(bodyUp, gravityUp) * transform.rotation;
                    transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, 50 * Time.deltaTime);
                    Rb.velocity += -gravityUp;
                }
                if (orbit.GetComponent<GravityArea>())
                {
                    MovementSpeed = 30.0f;
                }
                if (orbit.GetComponent<SphericalGravityArea>())
                {
                    MovementSpeed = 3000.0f;
                }
            }
            if (Input.GetKeyDown(KeyCode.E))
            {
                transform.position = teleportDestination.transform.position;
            }
            if (Input.GetKeyDown(KeyCode.Space))
            {
                ApplyGravity = false;
                jump = true;
                if (jump == true)
                {
                    if (canJump == true)
                    {
                        if (isGrounded == true)
                        {
                            Rb.AddForce(transform.up * 40000 * 1.2f * Time.deltaTime);
                            MovementSpeed = 5.0f;
                        }
                    }
                }
            }
            var mvfrwrd = false;
            if (gameObject)
            {

                if (Input.GetKey(KeyCode.UpArrow))
                {
                    mvfrwrd = true;
                    if (mvfrwrd == true)
                    {
                        moveZ = 1;
                    }
                }
                if (Input.GetKeyUp(KeyCode.UpArrow))
                {
                    moveZ = 0;
                    StartCoroutine(MoveWait());
                    Rb.velocity += Vector3.zero;
                    mvfrwrd = false;
                }
            }
            var mvbkwrd = false;
            if (gameObject)
            {

                if (Input.GetKey(KeyCode.DownArrow))
                {
                    mvbkwrd = true;
                    if (mvbkwrd == true)
                    {
                        moveZ = -1;
                    }
                }
                if (Input.GetKeyUp(KeyCode.DownArrow))
                {
                    moveZ = 0;
                    StartCoroutine(MoveWait());
                    Rb.velocity += Vector3.zero;
                    mvbkwrd = false;
                }
            }
            var mvlft = false;
            if (gameObject)
            {
                if (Input.GetKey(KeyCode.LeftArrow))
                {
                    mvlft = true;
                    if (mvlft == true)
                    {
                        moveX = -1;
                    }
                }
                if (Input.GetKeyUp(KeyCode.LeftArrow))
                {
                    moveX = 0;
                    StartCoroutine(MoveWait());
                    Rb.velocity += Vector3.zero;
                    mvbkwrd = false;
                }
            }
            var mvrght = false;
            if (gameObject)
            {

                if (Input.GetKey(KeyCode.RightArrow))
                {
                    mvrght = true;
                    if (mvrght == true)
                    {
                        moveX = 1;
                    }
                }
                if (Input.GetKeyUp(KeyCode.RightArrow))
                {
                    moveX = 0;
                    StartCoroutine(MoveWait());
                    Rb.velocity += Vector3.zero;
                    mvbkwrd = false;
                }
            }
        }
        dir = new Vector3(moveX, 0, moveZ);
        dir.Normalize();
        if (dir != Vector3.zero)
        {
            transform.forward = dir;
            Quaternion newRot = Quaternion.FromToRotation(dir, gravityUp);
            transform.rotation = Quaternion.Slerp(newRot, newRotation, 50 * Time.deltaTime);
        }
        if (moveX == -1)
        {
            Rb.velocity += -transform.right * MovementSpeed;
        }
        if (moveX == 1)
        {
            Rb.velocity += transform.right * MovementSpeed;
        }
        if (moveZ == -1)
        {
            Rb.velocity += -transform.forward * MovementSpeed;
        }
        if (moveZ == 1)
        {
            Rb.velocity += transform.forward * MovementSpeed;
        }
    }
    IEnumerator RespawnWait()
    {
        yield return new WaitForSeconds(3f);
        life = 3;
        ApplyGravity = false;
        transform.position = new Vector3(646, 69, 472);
        yield return new WaitForSeconds(1f);
        ApplyGravity = true;
    }
    IEnumerator MoveWait()
    {
        yield return new WaitForSeconds(1f);
    }
}

I had a problem with an if statement, if the player looks in the direction of movement the up vector of the transform won’t look in up direction of gravity, if the transforms up vector looks in the direction of gravity the player won’t look in the direction of movement.

This is the if statement:

if (dir != Vector3.zero)
        {
            transform.forward = dir;
            Quaternion newRot = Quaternion.FromToRotation(dir, gravityUp);
            transform.rotation = Quaternion.Slerp(newRot, newRotation, 50 * Time.deltaTime);
        }

I could just add this thread of code to the if statement:

transform.up = gravityUp;

But setting the direction of the up vector or lerping it cause a certain glitch to happen
So I wanted to try slerping the transform’s rotation.
What could I do to fix this

The glitch I was talking about makes the player align with the meridian of the planet which doesn’t happen in Super Mario Galaxy

This is why I’m thinking about slerping the transform rotation and not making any changes to the transform’s up vector directly.

A meridian is a line of longitude. Instead of being an east-west line like the equator, it travels from south to north.

Slerping seemed to fix the glitch. So how can I use slerping to make the transform’s up vector point in the direction of gravity, but have the forward vector point in direction of movement.

just make Quaternion.FromToRotation(dir, Vector3.up);.as this is always world up. transform.Up is the direction of the green arrow on the transform and you do not assign to it. It is read as a direction in world space.

Actually, I am assigning to the transform’s up vector.
But not directly like this:

transform.up = gravityUp;

transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, 50 * Time.deltaTime);Instead, I slerp the transform’s rotation.

Should I do:

transform.rotation = Quaternion.FromToRotation(dir, transform.up);

Again, I’m trying to make a game like Super Mario Galaxy which means using Vector3.up for spherical gravity is useless.

Please note that this is a forum and not a chat room. Please use the Edit Post feature as opposed to making many posts one after the other in a short span of time.

Thanks!

Don’t. It is what is messing you up. Gravity is transform.up in your case. You DO NOT assign that…you red it.

At some point you are aligning your character up with gravityUp, which is fine:

newRotation = Quaternion.FromToRotation(bodyUp, gravityUp) * transform.rotation;

After that, you are defining a “dir” vector, which was supposed to be a local vector since there is no y component (XZ movement):

dir = new Vector3(moveX, 0, moveZ);

And finally you are using that dir as your forward direction.

if (dir != Vector3.zero)
{
      transform.forward = dir;  //<-----
     Quaternion newRot = Quaternion.FromToRotation(dir, gravityUp);
     transform.rotation = Quaternion.Slerp(newRot, newRotation, 50 * Time.deltaTime);
}

BTW, Is that FromToRotation right? Shouldn’t that be LookRotation?

I think the problem is that “dir” is not being calculated from the character coordinates.
Try this:

dir = new Vector3(moveX, 0, moveZ);
if (dir != Vector3.zero)
{
     dir = transform.TransformDirection(dir);
     transform.forward = dir;
}