How to make orbital gravity

Hi I am looking to make orbital gravity so I can make a platformer like Super Mario Galaxy.


I already have some code I tried to make work but I don’t know what to look for when making this.


I have a setup with a physical sphere, a sphere trigger zone and a gravity point.

Also I have a character (which is a ball driven by physics) and 3 script’s I made myself.

1 for movement, 1 for the camera and 1 for the gravity rotation of the controlls and camera.


I hope any of you can help me with this.

I will post my code of my planet and my character movement here.

If you need any more info, let me know:


Planet point gravity

using UnityEngine;
using System.Collections;

public class PointGravity_Script : MonoBehaviour
{
    //Gravity point
    public GameObject gravityPoint;
    //PointGravity's gravity
    public float gravitySpeed;

    //Affected object detector
    public float GAObect;

    //Gravity affected objects detector
    private GameObject[] GAObects;

    private void OnCollisionEnter(Collision colA)
    {
        if (colA.gameObject.tag == "PlayerBall")
        {
            GAObect = 1;
            colA.gameObject.GetComponent<Rigidbody>().useGravity = false;
        }
    }

    private void OnCollisionStay(Collision colB)
    {
        if (colB.gameObject.tag == "PlayerBall")
        {
            colB.gameObject.GetComponent<Rigidbody>().AddForce((gravityPoint.transform.position - colB.gameObject.transform.position).normalized * gravitySpeed);
        }
    }

    private void OnCollisionExit(Collision colC)
    {
        if (colC.gameObject.tag == "PlayerBall")
        {
            GAObect = 0;
            colC.gameObject.GetComponent<Rigidbody>().useGravity = true;
        }
    }
}

Character movement

using UnityEngine;
using System.Collections;

public class BallController_Script : MonoBehaviour {

    //*Rigidbody to use
    private Rigidbody body;
    public float bodyZspeed;
    public float bodyXspeed;

    //Player input
    private float moveXinput = 0;
    private float moveYinput = 0;
    private bool jumpInput = false;

    //*Gravitation alteration variables
    //Used for rotation
    private float grafDirectionY = 0;
    private float grafDirectionX = 0;
    private float grafDirectionZ = 0;
    //Variables used for normalization of rotation's grafDirection (Normalization means the vectors axis are set to a scale of 0 to 1 where 1 is all the axis combined)
    private float grafDirection100Percent = 0;
    private float grafDirection1Percent = 0;
    //Used for jump (Jump does use negative values)
    private Vector3 grafDirection;

    //*Targeted objects
    public Transform CameraPivot;
    public Transform PlayerCamera;
    public Transform GravityPivot;

    //*Move by rotation variables
    //Acceleration/Deceleration
    public float accelerationSpeed = 0f;
    public float decelerationSpeed = 0f;

    //*Air movement
    //Acceleration
    public float airAccelerationSpeed = 0f;
    //Max velocity
    public float maxAirVelocity = 0f;
    //Temporary Vector
    private Vector3 tempVector;
    //Air moveInput
    private float airMoveXinput = 0;
    private float airMoveYinput = 0;


    //*Jump variables
    //The force wich is added overtime to jump
    public float jumpForce = 0f;
    //Some extra force used for opposite graf velocity
    public float jumpForceExtra = 0f;
    //How long the jump script will respond to Player input
    public float jumpTimeMax = 0f;

    //Used to reset jumpForce
    private float jumpForceBaseMemo = 0f;
    //How long the jump script is active
    private float jumpTime = 0f;
    //Used to block jump script
    private bool jumpNo = false;

    //*Collision variables
    //Stores the value of the last normal the object touches when it collided with a ground label object
    public Vector3 normal;
    //Used to store the angle betwean the up direction of gravity and the last touched normal
    public float normalAngle;
    //A variable used to see if the object is colliding with a ground label object
    public float Colide = 0;
    //Determines when the object may jump
    private bool onGround = false;
    //Delays the time the object isn't touching the ground (According to the offGround variable)
    public float offGroundDelay = 0;
    //Stores how long the object was actually off the ground before onGround is turned off
    private float offGroundTime = 0;
    //Stops the offGround script from looping
    private bool alreadyOffGround = true;

    void Start()
    {
        //Stores the start value of jumpForce
        jumpForceBaseMemo = jumpForce;
}

    void Update()
    {
        //*Set's rigidbody to use
        body = GetComponent<Rigidbody>();
        bodyZspeed = body.velocity.z;
        bodyXspeed = body.velocity.x;

        //*Gets gravity direction
        //Gets my GravityPivot script
        GravityPivot_Script gravityPivot_Script = GravityPivot.GetComponent<GravityPivot_Script>();
        //GrafDirection jump
        grafDirection = gravityPivot_Script.grafDirection;
        //GrafDirection rotation
        grafDirectionY = gravityPivot_Script.grafDirection.y;
        grafDirectionX = gravityPivot_Script.grafDirection.x;
        grafDirectionZ = gravityPivot_Script.grafDirection.z;
        

        //*Move by rotation
        //Get move input
        moveXinput = Input.GetAxis("Horizontal");
        moveYinput = Input.GetAxis("Vertical");

        //Get camera axis
        Vector3 CamF = PlayerCamera.forward;
        Vector3 CamR = PlayerCamera.right;

        //Inverts grafDirection if negative (I don't need to make a diffrence in up and down the camera axis will determine that)
        grafDirectionY = (grafDirectionY < 0) ? grafDirectionY * -1 : grafDirectionY;
        grafDirectionX = (grafDirectionX < 0) ? grafDirectionX * -1 : grafDirectionX;
        grafDirectionZ = (grafDirectionY < 0) ? grafDirectionZ * -1 : grafDirectionZ;

        //Normalizes grafDirection vector (Normalization means the vectors axis are set to a scale of 0 to 1 where 1 is all the axis combined)
        //determines what is value graph direction is as a whole
        grafDirection100Percent = grafDirectionY + grafDirectionX + grafDirectionZ;
        //calculates the smallest value in 0 to 1 form
        grafDirection1Percent = 1 / grafDirection100Percent;
        //calculates what percentage a grafDirection is compared to 100% in 0 to 1 form
        grafDirectionY = grafDirectionY * grafDirection1Percent;
        grafDirectionX = grafDirectionX * grafDirection1Percent;
        grafDirectionZ = grafDirectionZ * grafDirection1Percent;
        //turns 0 to 1 in 1 to 0 (This is to calculate how much a Cam vector axis is turned on)
        grafDirectionY = grafDirectionY * -1 + 1;
        grafDirectionX = grafDirectionX * -1 + 1;
        grafDirectionZ = grafDirectionZ * -1 + 1;

        //Turns a Cam vector axis on or off depending on the grafDirection (The axis that is in the same direction as the grafDirection is turned off)
        CamF.y *= grafDirectionY;
        CamR.y *= grafDirectionY;
        CamF.x *= grafDirectionX;
        CamR.x *= grafDirectionX;
        CamF.z *= grafDirectionZ;
        CamR.z *= grafDirectionZ;
        //Normalizes the Cam vector's (Normalization means the vectors axis are set to a scale of 0 to 1 where 1 is all the axis combined)
        CamF = CamF.normalized;
        CamR = CamR.normalized;

        //Checks if object is onGround and gets no move(X/Y)input and then if so it decreases the rotation speed
        if (moveXinput == 0 && moveYinput == 0)
        {
            if (onGround)
            {
                body.AddTorque(-body.angularVelocity * decelerationSpeed * Time.deltaTime);
            }
        }
        else //else it will add rotation force allong the camera axis (With the one that is in the grafDirection's direction turned off ofcourse)
        {
            body.AddTorque(CamR * moveYinput * accelerationSpeed * Time.deltaTime);
            body.AddTorque(CamF * moveXinput * -1 * accelerationSpeed * Time.deltaTime);
        }


        //*Air movement
        if(!onGround)
        {
            if (moveXinput != 0 || moveYinput != 0)
            {
                if (maxAirVelocity > CamF.x * body.velocity.x && maxAirVelocity > CamF.y * body.velocity.y && maxAirVelocity > CamF.z * body.velocity.z && moveYinput > 0)
                {
                    airMoveXinput = moveXinput;
                    airMoveYinput = moveYinput;
                    airMoveXinput = (airMoveXinput < 0) ? airMoveXinput * -1 : airMoveXinput;
                    airMoveYinput = (airMoveYinput < 0) ? airMoveYinput * -1 : airMoveYinput;
                    airMoveXinput = airMoveXinput * -1 + 1;
                    airMoveYinput = airMoveYinput * -1 + 1;

                    body.AddForce(CamF * moveYinput * airMoveXinput * airAccelerationSpeed * Time.deltaTime, ForceMode.Impulse);
                }
                if (maxAirVelocity > CamF.x * body.velocity.x * -1 && maxAirVelocity > CamF.y * body.velocity.y * -1 && maxAirVelocity > CamF.z * body.velocity.z * -1 && moveYinput < 0)
                {
                    airMoveXinput = moveXinput;
                    airMoveYinput = moveYinput;
                    airMoveXinput = (airMoveXinput < 0) ? airMoveXinput * -1 : airMoveXinput;
                    airMoveYinput = (airMoveYinput < 0) ? airMoveYinput * -1 : airMoveYinput;
                    airMoveXinput = airMoveXinput * -1 + 1;
                    airMoveYinput = airMoveYinput * -1 + 1;

                    body.AddForce(CamF * moveYinput * airMoveXinput * airAccelerationSpeed * Time.deltaTime, ForceMode.Impulse);
                }
                if (maxAirVelocity > CamR.x * body.velocity.x && maxAirVelocity > CamR.y * body.velocity.y && maxAirVelocity > CamR.z * body.velocity.z && moveXinput > 0)
                {
                    airMoveXinput = moveXinput;
                    airMoveYinput = moveYinput;
                    airMoveXinput = (airMoveXinput < 0) ? airMoveXinput * -1 : airMoveXinput;
                    airMoveYinput = (airMoveYinput < 0) ? airMoveYinput * -1 : airMoveYinput;
                    airMoveXinput = airMoveXinput * -1 + 1;
                    airMoveYinput = airMoveYinput * -1 + 1;

                    body.AddForce(CamR * moveXinput * airMoveYinput * airAccelerationSpeed * Time.deltaTime, ForceMode.Impulse);
                }
                if (maxAirVelocity > CamR.x * body.velocity.x * -1 && maxAirVelocity > CamR.y * body.velocity.y * -1 && maxAirVelocity > CamR.z * body.velocity.z * -1 && moveXinput < 0)
                {
                    airMoveXinput = moveXinput;
                    airMoveYinput = moveYinput;
                    airMoveXinput = (airMoveXinput < 0) ? airMoveXinput * -1 : airMoveXinput;
                    airMoveYinput = (airMoveYinput < 0) ? airMoveYinput * -1 : airMoveYinput;
                    airMoveXinput = airMoveXinput * -1 + 1;
                    airMoveYinput = airMoveYinput * -1 + 1;

                    body.AddForce(CamR * moveXinput * airMoveYinput * airAccelerationSpeed * Time.deltaTime, ForceMode.Impulse);
                }
            }
        }


        //*Jump
        //Get jumpInput
        jumpInput = Input.GetButton("Jump");

        //Checks if jump is not pressed and if object is not onGround; if so turns jump off
        if (!jumpInput && !onGround)
        {
            jumpNo = true;
        }

        //Jump script
        if (!jumpNo) //blocks jump script if necessary
        {
            if (jumpInput) //checks if jump is pressed
            {
                if (jumpTime < jumpTimeMax) //checks if jumpTime has not run out
                {
                    jumpTime += Time.deltaTime; //adds pased time to jumpTime

                    grafDirection = grafDirection.normalized * -1; //normalizes and inverts grafDirection (The jump direction is opposite to the gravity's direction of course)
                    
                    normal = normal.normalized; //normalizes normal (Normalization means the vectors axis are set to a scale of 0 to 1 where 1 is all the axis combined + the normal vector got normalized lol)
                    normalAngle = Vector3.Angle(grafDirection, normal); //calculates the angel betwean grafDirection and the normal (This is used to gradually turn on and off the scale of the grafDirection and the normal's influence)

                    if (normalAngle <= 90) //determines wether normalAngle is greater than 90 or not (Past 90 it reverses the efect of normal + grafDirection)
                    {
                        body.AddForce(grafDirection * normalAngle * jumpForceExtra * jumpForce * Time.deltaTime); //adds force in the grafDirection's direction (grafDirection scales up when the normalAngle becomes greater)(Uses jumpForceExtra to upscale the force since it has to fight gravity midair)
                        body.AddForce(normal * (-normalAngle + 180) * jumpForce * Time.deltaTime); //adds force in the normal direction (The normal variable scales down when the normalAngle becomes greater)
                    }
                    else
                    {
                        body.AddForce(grafDirection * (-normalAngle + 180) * jumpForceExtra * jumpForce * Time.deltaTime); //adds force in the grafDirection's direction (grafDirection scales up when the normalAngle becomes greater)(Uses jumpForceExtra to upscale the force since it has to fight gravity midair)
                        body.AddForce(normal * normalAngle * jumpForce * Time.deltaTime); //adds force in the normal direction (The normal variable scales down when the normalAngle becomes greater)
                    }
                }
            }
        }

        if (offGroundTime > 0)
        {
            offGroundTime -= Time.deltaTime;
            alreadyOffGround = false;
        }
        else
        {
            if (!alreadyOffGround)
            {
                onGround = false;
                alreadyOffGround = true;
            }
        }

        if (onGround)
        {
            jumpForce = jumpForceBaseMemo;
            jumpTime = 0f;
            jumpNo = false;
        }
    }

    private void OnCollisionStay(Collision colA)
    {
        if (colA.collider.tag == "Ground")
        {
            Colide = 1;
            onGround = true;
            normal = colA.contacts[0].normal;
        }
    }
    private void OnCollisionExit(Collision colB)
    {
        Colide = 0;
        if (colB.collider.tag == "Ground")
        {
            offGroundTime = offGroundDelay;
        }
    }
}

You can tune gravity vector for your individual character docs
You can create trigger colliders for planes, and when your character enters new trigger you can recalculate cumulative gravity vector for it as a sum of all vectors from each planet collider center positions to your character position (if you want your character to “feel” multiple gravity at once)