Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Ballistic - Problem with real trajectory

Discussion in 'Scripting' started by Nicolas-Liatti, Apr 25, 2016.

  1. Nicolas-Liatti

    Nicolas-Liatti

    Joined:
    Jun 19, 2013
    Posts:
    89
    Hi,

    I'm trying to throw an object following a trajectory, and it's getting me crazy because the object is not following the right trajectory.

    I just launch an object of 50.59 and a power of 10. According to the maths and physics, it should land 10m further (gravity of -9.81).

    The simulation works fine (blue) and lands exactly at the right point, but the object itself landed a few cm before (white) and has a different trajectory, as you can see on the screenshot:



    Code (CSharp):
    1. float angleToShoot;
    2. float power = 10;
    3.  
    4. void Throw(){
    5.  
    6. angleToShoot = 50.59f;
    7.  
    8. Vector3 shootDir = Quaternion.Euler (-50.59f, 0, 0) * Vector3.forward;
    9. force = shootDir * power;
    10.  
    11. GoToLaunch.transform.GetComponent<Rigidbody> ().velocity = force;
    12. GoToLaunch.transform.GetComponent<Rigidbody> ().useGravity = true;
    13.  
    14. }
    15.  
    16.  
    17. //Draw the "right" trajectory
    18. void OnDrawGizmos(){
    19.  
    20. float h = 0.0f;
    21.  
    22. while(transform.TransformPoint(PlotTrajectoryAtTime(h)).y >= 0){
    23.       Gizmos.DrawSphere(transform.TransformPoint(PlotTrajectoryAtTime(h)), 0.2f);
    24.        h = h + 0.1f;
    25. }
    26.  
    27. }
    28.  
    29.  
    30. public Vector3 PlotTrajectoryAtTime (float t) {
    31.        return force*t + Physics.gravity*t*t*0.5f;
    32. }
    33.  
    It's been driving me crazy for hours, I can't seem to find what's the problem...
    any help would be highly appreciated :(
     
  2. Nicolas-Liatti

    Nicolas-Liatti

    Joined:
    Jun 19, 2013
    Posts:
    89
    This is really weird, it seems that Unity 5.3.4 does not follow the same physics rule than in the past... is there a bug maybe?

    I made the following test:
    On one sphere I put this code:


    Code (CSharp):
    1. Void Start(){
    2.  
    3. Vector3 shootDir = Quaternion.Euler (-50f, 0, 0) * Vector3.forward;
    4. force = shootDir * 10;
    5.  
    6. GoToLaunch.transform.GetComponent<Rigidbody> ().velocity = force;
    7. }
    And on another one:

    Code (CSharp):
    1. float startTime;
    2. float force;
    3.  
    4. void Start(){
    5.    startTime = Time.time;
    6.  
    7.    Vector3 shootDir = Quaternion.Euler (-50f, 0, 0) * Vector3.forward;
    8.    force = shootDir * 10;
    9. }
    10.  
    11. void Update(){
    12.  
    13.         float t = Time.time - startTime;
    14.         transform.position = force * t + Physics.gravity * t * t * 0.5f;
    15.  
    16. }
    The 2nd sphere follows the right trajectory, but not the first one.
    This seems to mean that the velocity/physics in Unity 5.3.4 does NOT follow this physics formula: velocity * t + Physics.gravity * t * t * 0.5f ? It was working in previous versions AFAIK...

    Could someone test this and check if they have the same behavior? or let me know which obvious thing I am missing...?
     
  3. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,732
    Assuming drag is turned off?

    This is probably an aftefact of the fixed step simulation in Unity. The kinematic equations assume that a force is applied evenly over the life time of an object. Unity actually only applies this force every 0.02 seconds. The result is a very slight difference in trajectories.

    You can fix this by reducing the physics time step, or by by using an iterative solution to build the trajectory. Both of these come with computational overhead.

    It might be possible to use some discreet calculus tricks to come to the same solution in a single, non expensive equation. It's been a while since I did calc, so I couldn't point you in the right direction here.

    Or you could do a simple fudge factor empirically.
     
  4. Nigey

    Nigey

    Joined:
    Sep 29, 2013
    Posts:
    1,115
    Yeah for me I just made my own version trying to use the physics engine and came back with the same result (Using this):

    Code (CSharp):
    1.         protected float launchVelocity
    2.         {
    3.             get
    4.             {
    5.                 return Mathf.Sqrt(((_weaponRange * -Physics.gravity.y) / Mathf.Sin(2 * 45))) * projectile.GetComponent<Rigidbody>().mass;
    6.             }
    7.         }
    8.  
    9.         protected float LaunchAngle(float _targetDistance)
    10.         {
    11.                 return (Mathf.Rad2Deg * Mathf.Asin( ((_targetDistance * -Physics.gravity.y) / Mathf.Pow(launchVelocity, 2)) ) );
    12.         }
    So for me in the end I created my own ballistics physics engine. Purely for ballistics.
     
  5. Nicolas-Liatti

    Nicolas-Liatti

    Joined:
    Jun 19, 2013
    Posts:
    89
    The problem indeed comes from Timestep.
    Depending on its value, the results are very different... If I set the tilmestep to 0.01 instead of 0.02 I have closer results, although still not perfect.

    This means the simulation cannot rely on
    launchvelocity * t + Physics.gravity * t * t * 0.5f

    I need to find a way to temper it to reflect Unity physics... any idea what might be the formula?
     
  6. Zaflis

    Zaflis

    Joined:
    May 26, 2014
    Posts:
    436
    You're using slightly different angles for both, why? -50.59f and -50f.
     
  7. Nicolas-Liatti

    Nicolas-Liatti

    Joined:
    Jun 19, 2013
    Posts:
    89
    This is just a different example, but this is the same angle in both scripts.

    The main issue I have is that the simulation calculation is based on real physics, with launchvelocity * t + Physics.gravity * t * t * 0.5f. And I think I need to adapt it to use Time.fixedTime, with the time used by Physics.

    Bu I don't manage to do it so far...
     
unityunity