Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

2D Unrealistic Orbit Problem. (First time poster

Discussion in 'Physics' started by wesleyrichmond, Jun 9, 2017.

  1. wesleyrichmond

    wesleyrichmond

    Joined:
    Jun 9, 2017
    Posts:
    4
    Hello Unity Community,

    I am trying to make a simple 2D game with Newtonian physics. My first project is to have a ship which orbits a planet and can thrust and change the orbit.

    I successfully got my ship to orbit the planet, however the orbit is not elliptical but is in the pattern of a mathematical rose or rhodonea curve.

    If anyone can please help me, I would like to know how to get a real elliptical orbit and I would like to know why I am getting the rhodonea curve.

    Here is my orbit code (mostly taken from unitywiki):


    Code (CSharp):
    1.  
    2. public float range = 10f;
    3.  
    4.     Rigidbody2D planetRb;
    5.  
    6.     void Start()
    7.     {
    8.         planetRb = GetComponent<Rigidbody2D>();
    9.     }
    10.  
    11.     void FixedUpdate()
    12.     {
    13.         Collider2D[] gravityCircleArray = Physics2D.OverlapCircleAll(transform.position, range);
    14.         List<Rigidbody2D> listOfAffected = new List<Rigidbody2D>();
    15.  
    16.         foreach (Collider2D c in gravityCircleArray)
    17.         {
    18.        
    19.             Rigidbody2D ship = c.attachedRigidbody;
    20.             if (ship != null && ship != planetRb && !listOfAffected.Contains(ship))
    21.             {
    22.                 listOfAffected.Add(ship);
    23.                 Vector3 offset = transform.position - c.transform.position;
    24.                 offset.Normalize();
    25.                 float distance = Vector3.Distance(transform.position, c.transform.position);
    26.                 ship.AddForce(offset * planetRb.mass / distance);
    27.  
    28.             }
    29.         }
    30.     }
     
  2. trudeaudm

    trudeaudm

    Joined:
    Apr 17, 2013
    Posts:
    116
    Does the planet move?
     
    wesleyrichmond likes this.
  3. wesleyrichmond

    wesleyrichmond

    Joined:
    Jun 9, 2017
    Posts:
    4
    No the planet is not moving at all. The transform remains the same.

    I changed the last line to this:
    ship.AddForce(distance * c.GetComponent<Rigidbody2D>().mass * (planetRb.mass/100) / gravConstantDivider);

    I thought that it worked at first until I realized that the planetary body was stuck at the semi major axis no matter what i did.
     
  4. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    5,984
    What you're referring to is called precession, and it happens (usually to a tiny extent) in all real orbits.

    To understand why you're getting it, just look at the following curve, and imagine a planet following this path:



    It's clear that since the planet moves directly through the center, it cannot possibly avoid precession, because to follow the exact same path as before would require an instantaneous change in direction and momentum at the 'pointy' end which isn't going to happen.

    So basically, a non-precessing elliptical orbit is one where the rotating body (planet) must enter the situation with the exact balance of initial conditions (speed, mass and direction) required to achieve a non-precessing orbit - i.e. you must set the initial conditions precisely.

    I'm not quite sure right now how to calculate that but it won't be very easy. This might be of help.

    Also be aware that Unity's physics might not be up to the task of maintaining the precise conservation of momentum required to achieve a stable non-precessing orbit. So you might end up having to 'reset' it periodically.
     
    wesleyrichmond likes this.
  5. trudeaudm

    trudeaudm

    Joined:
    Apr 17, 2013
    Posts:
    116
    So a few things, I think it all comes down to your math for applying force to the orbiting object.

    1. Vector3 offset = transform.position - c.transform.position;
    2. offset.Normalize();
    3. float distance = Vector3.Distance(transform.position, c.transform.position);
    4. ship.AddForce(offset * planetRb.mass / distance);
    First off you need to multiply the mass of the object you have orbiting by everything as well. Otherwise a more massive object will be affected by the gravity less.

    This is the function I use to apply gravity to objects, this function is designed so you can set the gravity for a surface gravity. IE some gravity value at a set distance from the center of the planet.

    Code (CSharp):
    1.  
    2. public float surfaceGravity;
    3. float d = Vector2.Distance (orbitingObject.transform.position, planet.transform.position);
    4. orbitingObject.AddForce ((planet.transform.position - orbitingObject.transform.position).normalized * surfaceGravity * orbitingObject.mass * Mathf.Pow (planetRadius, 2f) / Mathf.Pow(d, 2f));
    To just use your code instead of:
    Code (CSharp):
    1. ship.AddForce(offset * planetRb.mass / distance);
    2.  
    Do:
    Code (CSharp):
    1. ship.AddForce(offset / (distance*distance) * planetRb.mass);
    Although I recommend adding the ships mass in case you have ships with different masses.
    Code (CSharp):
    1. ship.AddForce(offset / (distance*distance) * planetRb.mass * ship.mass);
     
    Last edited: Jun 10, 2017
    Billy4184 and wesleyrichmond like this.
  6. wesleyrichmond

    wesleyrichmond

    Joined:
    Jun 9, 2017
    Posts:
    4
    Thanks Trudeau! Because of your help I was able to go from this:



    to this (drawn with debug line):



    and thanks billy for telling me what a precession is, I had no idea.


    A few additional questions if you don't mind:

    In your code, Trudeau, you have this:
    Code (CSharp):
    1.  
    2. Mathf.Pow(planetRadius, 2f) / Mathf.Pow(d, 2f);
    3.  
    why are you using the planetRadius in your equation? I don't understand how that is a significant factor.

    Also, do either of you have an idea on how do calculate the semi-major axis and height of periapsis and apoapsis of a particular orbit?

    Code (CSharp):
    1.  
    2. semiMajorAxis = -(gravConstantDivider * planetDistanceVector * planetaryRb.mass) / ((planetDistanceVector * (shipVelocity.magnitude * shipVelocity.magnitude)) - (2 * gravConstantDivider * planetaryRb.mass));
    3.  
    I wrote in this horrible mess to figure out the semiMajorAxis using my velocity and the planets mass but it seems to pop out inconsequential numbers.
     

    Attached Files:

  7. trudeaudm

    trudeaudm

    Joined:
    Apr 17, 2013
    Posts:
    116
    That code was setup for specific use in a project where I wanted to be setting the gravity of a planet as a direct value, and have that amount of force be the gravity at the surface of the planet.

    So say I had a planet that I wanted to have 1G on the surface. The distance from the center of the planet to the surface would be the planetRadius value. And the surfaceGravity value I could set in the inspector to 1, or whatever value I wanted the gravity to be on the surface.

    In regards to your other question about semi major axis distances and such I will have to consider that tomorrow, to tired right now.