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. Dismiss Notice

Precalculate trajectory

Discussion in 'Physics' started by Ambrose998800, Nov 16, 2020.

  1. Ambrose998800

    Ambrose998800

    Joined:
    Jun 23, 2015
    Posts:
    59
    Hi there!

    I need some help to correct my fly-path script. In my game, you sail the cosmic stormwinds and (because a solarsail don't work like a nautical sail, you can't sail against the winds) you have to flap in the sails and make fly-by and slingshot maneuvers using asteroids to come around. All works with 'correct' physics, no torque or some other stuff added directly to the rigidbody, the whole steering and flying process works just with force at position and the lever action principle over sails, steering thrusters and steering paddles (that works perfectly).
    For the human behind it (the player), not everything is quite easy to calculate, so I need a fly path calculator that the player can set up his next maneuver. Sadly I'm no space-engineer and just know some basics in physics.

    The fly-by physics are working and make use of the gravitational law: F = (G*M1*M2)/Distance
    The same calculation I use for the flying rigidbody (spaceship) are used for the path calculations.

    Here is a screenshot from the current results:

    SpaceSimulator - PathCalculation.png

    The orange line is the path the rigidbody flew, the rigidbody is where the axis-arrows are displayed. The three blue lines that are tangent to the orange line are snapshots of the calculated fly-path made seconds before the screenshot to checking the calculation against the actual outcome. As you can see, they predict the rigidbody will flee the gravity pool.

    Sometimes the precalculation is wrong the other side:

    SpaceSimulator - WrongPath.png

    Here the precalculated path is too narrow.

    The calculations are made as follows: the first section extends the current rigidbodys velocity (direction & magnitude), every following flag (point in the path) is calculated by the direction and magnitude of the last section, then checked if gravitational field takes effect, then, if needed, updated with the shift due to gravity forces, and so on. I may forgot some things like solver iterations and stuff - I'm a mechanic, never learned programming, all done by learning by doing. So, some help or hints would be great!

    Here is the current fly-path script:

    Code (CSharp):
    1. public class PathCalculator : MonoBehaviour
    2. {
    3.     public LineRenderer PathLine;
    4.  
    5.     public Vector3 Offset = new Vector3(5f, 0f, 0f);
    6.  
    7.     public float PathLength = 1000f;
    8.  
    9.     public float FlagDistance = 25f;
    10.  
    11.     public int FlagCount;
    12.  
    13.     Rigidbody Rb;
    14.  
    15.     void Start()
    16.     {
    17.         Rb = GetComponent<Rigidbody>();
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         if (Input.GetKeyDown(KeyCode.T)) PathSnapshot();
    23.  
    24.         //Count flags
    25.         FlagCount = Mathf.RoundToInt(PathLength / FlagDistance);
    26.  
    27.         //Create array to store flags
    28.         Vector3[] Flags = new Vector3[FlagCount];
    29.  
    30.         //Adjust line renderer position array
    31.         PathLine.positionCount = FlagCount;
    32.  
    33.         //Get local offset for the starting point
    34.         Vector3 LocalOffset = transform.TransformVector(Offset);
    35.  
    36.         //Get the initial velocity for the first section
    37.         Vector3 Direction = Rb.velocity.normalized;
    38.  
    39.         //Get the initial speed for the first section
    40.         float Speed = Rb.velocity.magnitude;
    41.  
    42.         //Avoid zero-calculations
    43.         if (Direction == Vector3.zero) Direction = transform.forward;
    44.  
    45.         //Iterate through all flags of the flight-path
    46.         for (int i = 0; i < FlagCount; i++)
    47.         {
    48.             //Starting position at the spaceship
    49.             if (i == 0) Flags[0] = transform.position + LocalOffset;
    50.  
    51.             //First section with the current rigidbodys parameter
    52.             if (i == 1) Flags[1] = transform.position + LocalOffset + Direction * Speed;
    53.          
    54.             //Go on...
    55.             if (i > 1)
    56.             {
    57.                 //Get last calculated velocity (direction & magnitude)
    58.                 Vector3 Velocity = Flags[i - 1] - Flags[i - 2];
    59.  
    60.                 //Extend the last flag like no gravitational influence would take effect
    61.                 Flags[i] = Flags[i - 1] + Velocity;
    62.  
    63.                 //Get a shift if gravity takes effect
    64.                 Vector3 PositionShift = GravitationalShift(Flags[i]);
    65.  
    66.                 //Change the new flag position due to effect of gravity
    67.                 if (PositionShift != Vector3.zero)
    68.                 {
    69.                     Flags[i] += PositionShift;
    70.                 }
    71.             }
    72.         }
    73.  
    74.         //Pass positions to the line renderer
    75.         PathLine.SetPositions(Flags);
    76.  
    77.         //Display flags & NoGravs
    78.         for (int i = 0; i < FlagCount; i++) if (i > 0) Debug.DrawLine(Flags[i - 1], Flags[i], Color.yellow);
    79.     }
    80.  
    81.     Vector3 GravitationalShift(Vector3 CurrentPosition)
    82.     {
    83.         Vector3 Shift = Vector3.zero;
    84.  
    85.         //Get source of gravity
    86.         Collider[] Cols = Physics.OverlapSphere(CurrentPosition, 10f, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Collide);
    87.              
    88.         Transform GravitationalObject = null;
    89.  
    90.         //Check for gravitational field triggers
    91.         foreach (Collider Col in Cols)
    92.         {
    93.             if (Col.isTrigger && Col.gameObject.GetComponent<GravityField>())
    94.             {
    95.                 GravitationalObject = Col.transform;
    96.  
    97.                 break;
    98.             }
    99.         }
    100.  
    101.         //Calculate influences
    102.         if (GravitationalObject != null)
    103.         {
    104.             Vector3 Direction = (GravitationalObject.position - CurrentPosition).normalized;
    105.  
    106.             float Distance = Vector3.Distance(GravitationalObject.position, CurrentPosition);
    107.  
    108.             float Force = GetGravitationalValues.ForceAtDistance(GravitationalObject.GetComponent<GravityField>().Tonnes * 1000f, Rb.mass, Distance);
    109.  
    110.             Shift = Direction * Force;
    111.         }
    112.  
    113.         //Return shift due to effect of gravity
    114.         return Shift;
    115.     }
    116.  
    117.     void PathSnapshot()
    118.     {
    119.         GameObject SnapShot = Instantiate(PathLine.gameObject);
    120.     }
    121. }
    And here the gravity force calculations:

    Code (CSharp):
    1. public class GetGravitationalValues
    2. {
    3.     //Gravitational constant
    4.     static readonly float G = 6.672f * Mathf.Pow(10, -11);
    5.  
    6.     public static float ForceAtDistance(float Mass1, float Mass2, float Distance)
    7.     {
    8.         //Gravitational force at certain distance
    9.         return (G * Mass1 * Mass2) / Distance;
    10.     }
    11.  
    12.     public static float DistanceForForce(float ForceValue, float Mass)
    13.     {
    14.         //The distance where the force has a certain value
    15.         return (G * Mass) / ForceValue;
    16.     }
    17. }
     
    Last edited: Nov 16, 2020
  2. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    927
    Not related to your problem, but in my opinion, you shouldn't use real-world values especially astronomical values due to floating-point error, you should use some kind of proportional values like instead of using 10^24 kg for the earth and multiplying it to 10^-11 for G instead, use some arbitrary values in the range of floats or consider using decimal or doubles
     
  3. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,580
    If I remember correctly, you need to include delta t in your prediction calculations. It is related to time step. There was subject while ago, discussing it.
    I had my own physics based path prediction working long time ago. But I don't remember details now, unfortunately.
    Also as mentioned, avoid real world values. Floating point erorr will kill your path.
    Think about smoke and mirrors, when you can.
     
    Last edited: Nov 17, 2020
    Ruchir likes this.
  4. Ambrose998800

    Ambrose998800

    Joined:
    Jun 23, 2015
    Posts:
    59
    Thanks for that input Ruchir. Thats exactly the valuable things to learn, the limits and workarounds! Thats for sure one thing to adjust.

    And include the time was something I had in mind, but didn't know how it is working with each other - I thought, if I run both calculation and rigidbody influence on FixedUpdate or Update, they would come out with the same result. Read later that rigidbody solver iterations may not be the same as FixedUpdates. Of course that has a huge influence regarding the result...
     
  5. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    464
    You also instantiate an extra physics scene and simulate ahead. Depending on the complexity of your scene, the second simulation might be computationally cheap since there are not many rigid bodies and almost no collisions.

    https://learn.unity.com/tutorial/multi-scene-physics
     
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,580
  7. Ambrose998800

    Ambrose998800

    Joined:
    Jun 23, 2015
    Posts:
    59
    Well, finaly I made it...
    To be honest; I lost my whole project due to an computer update and my own stupidity. I see losses as new chances, so I moved on. After some hours I rewrote the script - this time working! The issue was to take the time into account (at this point big thanks to Antypodish!). The script can calculate multiple gravity fields overlapping, in real time:

    Working Gravity Trail - 01.png
    [The path ahead]

    Also I can calculate the speed gain and loss of a fly-by maneuver...

    Working Gravity Trail - 02.png
    [speed value in gray]

    And the best is, to calculate the path takes only around 0.02 - 0.06 ms, cause I split the calculation into multiple parts with cooldowns in between.

    Bild_2021-08-17_183848.png
    [CalculatePath does the magic]

    I have to say, I'm happy with the results. I solved a problem of first-lession-physic-students by myself xD
    Thanks to all responder!
     
    Ruchir likes this.