Infinity run around something

Hello! I’m trying to implement a something similar to this Space Runner - Demo 4 by Bit Botz Games but I stuck with needing of player to run around the planet then jump and get magnitized to other planet.
So could you help me by tell how to make player run around planet and magnitize player to it?

After playing the game for about 4 hours, I finally understand how it works!


The main thing you need to do is to rotate the player so that its feet point towards the center of the planet. Then, you can add a force downwards on the player so that it creates some sort of magnetic pull, towards the planet. Pretty nice!


Here’s my script:

[RequireComponent(typeof(Rigidbody2D))]
public class PhysicsController : MonoBehaviour
{
    Rigidbody2D rb;

    Vector2 PlanetCenter;
    public Transform Planet;

    public float Gravity;
    public float MovementSpeed;
    public float JumpForce;

    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void Update()
    {
        // Gravity
        rb.AddForce(transform.up * Gravity);

        // Movement
        rb.AddForce(-transform.right * MovementSpeed);

        if (Input.GetKeyDown(KeyCode.Space))
            rb.AddForce(-transform.up * JumpForce);

        #region Calculate angle

        Vector2 Direction = new Vector2
        (
            PlanetCenter.x - transform.position.x,
            PlanetCenter.y - transform.position.y
        );

        // Fancy maths stuff:
        // https://onlinemschool.com/math/library/vector/angl/#:~:text=The%20cosine%20of%20the%20angle,the%20product%20of%20vector%20magnitude.

        // Cosine of look angle = Dot product of vectors / Mulitplication of vector magnitudes

        float DotProduct = Vector2.Dot(Vector2.up, Direction);

        float MagnitudeUp = Vector2.Distance(Vector2.zero, Vector2.up);
        float MagnitudeVelocity = Vector2.Distance(Vector2.zero, Direction);
        float CombinedMagnitude = MagnitudeUp * MagnitudeVelocity;

        float CosineOfAngle = DotProduct / CombinedMagnitude;
        float Angle = Mathf.Acos(CosineOfAngle) * Mathf.Rad2Deg;

        #endregion

        #region Rotate player

        if (transform.position.x < PlanetCenter.x)
            transform.rotation = Quaternion.Euler(0, 0, 360 - Angle);
        else
            transform.rotation = Quaternion.Euler(0, 0, Angle);

        #endregion
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        Planet = collision.collider.gameObject.transform;
        PlanetCenter = Planet.position;
    }
}

This is the player script. A big chunk of it is some fancy math stuff. Some other things you might want to know is that the planet I have is just a circle collider 2D, with a frictionless physics2D material. The player’s rigidbody2D also has a gravity scale of 0, as I want to manually create my own gravity. Finally, the rigidbody’s z rotation is locked in the constraints menu of the rigidbody 2D component. Have fun messing around with the movement speed etc. @akilaydin2

It seems as though the player exists in one of two forms of physics / gravity. They will either be inside a planets gravitational zone in which the downwards gravity will be in the vector between the planet centre and the player. Or they will be in empty space where they keep moving in the direction in which they started.

A very important little utility function you’ll need for this project is a rotation function for 2d vectors:

// thanks to https://answers.unity.com/questions/1229302/rotate-a-vector2-around-the-z-axis-on-a-mathematic.html

Vector2 Rotate(Vector2 aPoint, float aDegree)
 {
     float rad = aDegree * Mathf.Deg2Rad;
     float s = Mathf.Sin(a);
     float c = Mathf.Cos(a);
     return new Vector2(
         aPoint.x * c - aPoint.y * s,
         aPoint.y * c + aPoint.x * s;
     );
 }

I’d start by getting the planet physics working; have the player run around a given point at a given radius, have jumping work when gravity is towards the planet centre rather than in the global downwards direction. If I were you I would handle the planet running using angles rather than offsets (as you might in usual platformers): when you know the planet’s radius, you can find its circumference and then you can find how long it should take the player to move around it and finally from that you can calculate how much angular change they require each time step.

private void MovePlayer(float speed, float planetRadius, Vector2 planetCentre)
{
    // speed is in meters per second, say it's 0.5 here
    // if the radius of the planet is 10 meters
    // then the circumference is PI * diameter = 3.14 * 20 = 62.8
    float circumference = Mathf.PI * planetRadius * 2f;

    // if the player moves at 0.5 meters per second:
    // then the time to orbit the planet will be t = distance / speed
    // time = 62.8 / 0.5 = 125.6
    float orbitTime = circumference / speed;

    // so the angle change each second will be s = 360 / 125.6 = 2.86 degrees
    float deltaAngle = 360f / orbitTime;
    
    // need to know planet centre, radius and player's current angle around planet to determine new position
    playerAngle += deltaAngle;
    transform.position = planetCentre + Rotate(Vector2.up, playerAngle) * planetRadius;

    // playerAngle changes in this function so is not passed in as an argument, you can make it a ref argument if you like
}

Then look at hopping between planets; if the player exceeds a planet’s gravity zone then they switch to open space physics, if they enter a new planets gravity zone then they’ll start falling towards that one.

Finally you can add the obstacles, the hazards shouldn’t be too hard; if the player hits them they die. The ones that stop running are a little more interesting.