Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Resolved Question about orbital mechanics in unity

Discussion in 'Physics' started by Ladidadi8, Nov 17, 2022.

  1. Ladidadi8

    Ladidadi8

    Joined:
    Nov 6, 2017
    Posts:
    2
    Hi, I have trouble understanding part of code I got from another forum post about orbiting physics, and CodeMonkeys orbiting simulator tutorial.

    I can't figure out why I get same result with two different formulas. I'm also using Orbiting debugger from codemonkey so I can see what orbit I should be get if everything is done correctly.

    Here is my code:

    Code (CSharp):
    1.     void Start()
    2.     {
    3.         rb = GetComponent<Rigidbody2D>();
    4.  
    5.         planetMass = rb.mass;
    6.  
    7.         if (useInitialVelocity)
    8.         rb.velocity = initialVelocityDirection * initialVelocityAmount;
    9.  
    10.         velocity = rb.velocity;
    11.  
    12.         foreach(GravityTest planet in FindObjectsOfType<GravityTest>())
    13.         {
    14.             planets.Add(planet.GetComponent<Rigidbody2D>());
    15.         }
    16.     }
    17.  
    18.     public void GravityWithVelocity()
    19.     {
    20.         Vector3 acceleration = Vector3.zero;
    21.         foreach (Rigidbody2D star in planets)
    22.         {
    23.             if (star.position != rb.position)
    24.             {
    25.                 Vector3 forceDir = (star.position - rb.position).normalized;
    26.                 float sqrDst = (star.position - rb.position).sqrMagnitude;
    27.                 acceleration += forceDir * .001f * star.mass / sqrDst;
    28.             }
    29.         }
    30.  
    31.         velocity += acceleration;
    32.         rb.velocity = velocity * Time.fixedDeltaTime;
    33.     }
    34.  
    35.     private void GravityWithForce()
    36.     {
    37.         foreach(Rigidbody2D star in planets)
    38.         {
    39.             if(star.position != rb.position)
    40.             {
    41.                 float r = Vector3.Distance(star.position, rb.position);
    42.                 float totalForce = -(.001f * star.mass * rb.mass) / (r * r);
    43.                 Vector3 force = (rb.position - star.position).normalized * totalForce;
    44.                 rb.AddForce(force);
    45.             }
    46.         }
    47.     }
    48.  
    So the question is why is formula in GravityWithVelocity missing mass of the planet that is orbiting the star and producing same result as GravityWithForce?

    Edit: So as soon as I posted I figured out that the formula is different for calculating velocity vs force. My first tought was that I have issue with code from tutorial that I attempted to simplify for my purposes. I still don't really understand physics behind it, but all that matters is that code is correct!
     
    Last edited: Nov 17, 2022
  2. leebissessar5

    leebissessar5

    Joined:
    Nov 15, 2022
    Posts:
    48
    The gravitational force that acts between two masses m_R and m, where m_R is the mass of the rigid body under observation, is given by F_G = -G*m_R*m/r^2, where r is the distance between the two masses and G is the gravitational constant. Your GravityWithForce() method pretty much uses this formula and calculates the total contributions of the gravitational force of each mass with respect to the rigid body and applies this force to it.

    GravityWithVelocity() computes the acceleration due to the force using simple Newton's 2nd Law (F = ma). Dividing both sides by m_R, since you want to find its acceleration, this gives a = -G*m/r^2. Acceleration is the derivative of velocity, so you find the net acceleration (line 27) then use an ODE solver to find velocity. It looks like you're using Forward Euler but the actual formula is: f(x_t) = f(x_t-1) + h*f'(x), where x_t is the state at the current timestep, x_t-1 is the state in the previous timestep, and h is the time step (appropriately Time.fixedDeltaTime as you did). At t = 0, you need to place an initial condition, so your code should be something like:

    Code (CSharp):
    1. void Start() {
    2.      // everything else
    3.      rb.velocity = 0;    // initial condition
    4. }
    5.  
    6. void GravityWithVelocity() {
    7.    // lines 20-31
    8.    rb.velocity = rb.velocity + acceleration*Time.fixedDeltaTime;
    9.   // or rb.velocity += acceleration*Time.fixedDeltaTime;
    10. }
    I think relying on GravityWithForce() is better in the long run, as implementing differential equations of dynamical systems is not worth the hassle when you could just understand what the equations are saying and apply all the forces to achieve the same result. Assigning rb.velocity is not recommended, people in the forums will tell you this and I learnt the hard way trying to implement a massive state space model in Unity.
     
    Last edited: Nov 18, 2022
    Ladidadi8 and Edy like this.
  3. Ladidadi8

    Ladidadi8

    Joined:
    Nov 6, 2017
    Posts:
    2
    This is exactly the kind of explanation I was looking for, thank you. As you said adding force seems to be a lot easier to understand, and changing velocity seems like additional step to get same result.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,589
    Just to state for the record here, it's not so much as not being recommended, it's that just like anything in code, if you directly write over a field, property (etc) you're replacing what information was there before.

    In the case of the velocity of a Rigidbody, you're replacing its current velocity with one of your own choosing therefore loosing the information it had which might be the forces being applied elsewhere via the scripts or from collisions or the effects of gravity etc.
     
    Ladidadi8 likes this.