Search Unity

Calculating trajectory angle to hit target position - Angle always -90?

Discussion in 'Physics' started by SovietSpartan, Dec 11, 2015.

  1. SovietSpartan

    SovietSpartan

    Joined:
    May 2, 2014
    Posts:
    17
    Hello, i've been breaking my head the last few nights trying to get an aiming system for a World of warships-esque game.

    The main idea is that the player points through a crosshair to a target destination (These sometimes can exceed 3000+ meters) and the character he/she is using must point torwards the necessary angle to hit the target position in 3D space.

    Since the character always turns torwards the target destination, the former is always in the line of fire so the trajectory of the projectile is a 2D parabola.

    I tried to implement the equation found here https://en.wikipedia.org/wiki/Traje...#Angle_required_to_hit_coordinate_.28x.2Cy.29 but the angle always comes out as -90 Degrees. I checked the code countless times but i just can't find anything wrong.

    If its any help, my projectile has a mass of 2, and it's fired at a speed of 570 m/s (which is assigned by doing a rigidody.velocity = shootPosition.transform.forward*570).

    Here's the code:

    Code (CSharp):
    1.     float getAngle(){
    2.         float x = Vector3.Distance(endPos,startPos);
    3.         float y = endPos.y;
    4.         float z = endPos.z;
    5.         float vel = speed;
    6.  
    7.         float angle01;
    8.         float angle02;
    9.         float angleResult;
    10.  
    11. // Calculate the angles, then pick the lowest one so we don't end up pointing at 90 degrees
    12.         angle01 = Mathf.Atan((Mathf.Pow (vel, 2) + Mathf.Sqrt (Mathf.Pow (vel, 4) - (Physics.gravity.y * (Physics.gravity.y * Mathf.Pow (x, 2) + (2 * y) * Mathf.Pow (vel, 2))))) / (Physics.gravity.y * x));
    13.  
    14.         print ("Angle 01 : " + angle01);
    15.  
    16.         angle02 = Mathf.Atan((Mathf.Pow (vel, 2) - Mathf.Sqrt (Mathf.Pow (vel, 4) - (Physics.gravity.y * (Physics.gravity.y * Mathf.Pow (x, 2) + (2 * y) * Mathf.Pow (vel, 2))))) / (Physics.gravity.y * x));
    17.  
    18.         print ("Angle 02 : " + angle02);
    19.  
    20.         angleResult = Mathf.Min (angle01,angle02);
    21.  
    22.         print ("Angle : " + angleResult*Mathf.Rad2Deg);
    23.         return angleResult * Mathf.Rad2Deg;
    24.     }

    Thanks in advance for any help!!
     
  2. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    You realise you picked the lob formula over the easier to implement and more likely intended angle of reach formula.

    The formula you picked would be used if you wanted the projectile to come down on top of the target, rather than angle of reach which fires directly at the target, putting enough angle to counter distance/gravity.

    I have working code for lob around. not here. can post if you cant get it right. I ended up breaking it down into multiple parts rather than doing it one line of code. I suspect you missed some braces, but I cbf getting my head around it...
     
  3. SovietSpartan

    SovietSpartan

    Joined:
    May 2, 2014
    Posts:
    17
    Seems like angle of reach is the right path for me, haha.
    I tried the Angle of reach formula from the wiki page i posted up there. However now the angle is always 0 degrees.
    I forgot to mention that there's a height difference between the shooting position and the target position which i'm believing has something to do with it.
    Here's the code so far:
    Code (CSharp):
    1.     float getAngle(){
    2.         float gravity = Physics.gravity.y;
    3.         float distance = Vector3.Distance (endPos, startPos);
    4.         float angle = (1/2)*Mathf.Asin ((gravity * distance) / (speed*speed));
    5.         return angle*Mathf.Rad2Deg;
    6.     }
    What could be wrong now?
     
  4. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    Code (csharp):
    1.  
    2.  
    3.     public static bool CalculateTrajectory(float TargetDistance, float ProjectileVelocity, out float CalculatedAngle)
    4.     {
    5.         CalculatedAngle = 0.5f * (Mathf.Asin ((-Physics.gravity.y * TargetDistance) / (ProjectileVelocity * ProjectileVelocity)) * Mathf.Rad2Deg);
    6.         if(float.IsNaN(CalculatedAngle))
    7.         {
    8.             CalculatedAngle = 0;
    9.             return false;
    10.         }  
    11.         return true;
    12.     }
    13.  
    14.  
     
    Danirey likes this.
  5. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    here's the messy (un-optimised) lob code I wrote a way back as well.
    Code (csharp):
    1.  
    2.  
    3.         float actualDistance = Vector3.Distance(transform.position, TargetCenter);
    4.        
    5.         float v = WeaponSystem.Projectile.Velocity;
    6.         float g = Physics.gravity.y;
    7.         float x = actualDistance;
    8.         float y = 0;
    9.        
    10.         float v2 = v * v;
    11.         float v4 = v * v * v * v;
    12.        
    13.         float gx2 = g * x * x;
    14.         float yv2 = 2 * y * v * v;
    15.         float gx = g*x;
    16.        
    17.         float res =  Mathf.Sqrt(v4 - g * (gx2 + yv2));
    18.         float res1 = v2 + res;
    19.         float res2 = res1 / gx;
    20.        
    21.         float trajectoryAngle = Mathf.Atan(res2) * 180 / Mathf.PI;
    22.        
    23.         if(float.IsNaN(trajectoryAngle))
    24.         {
    25.             trajectoryAngle = 0;
    26.    
    27.         }
    28.  
    29.  
     
    Danirey likes this.
  6. SovietSpartan

    SovietSpartan

    Joined:
    May 2, 2014
    Posts:
    17
    The angle of reach code is the one i need it seems.
    I managed to get it working, however the problem now is that there's a height difference, and the formula doesn't take that into account. I tried investigating on it but i can't find any answers on it.

    Any help on that is totally appreciated! :)
     
  7. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    The formula doesnt need to account for height difference.

    If its not hitting accurately, its more likely that the center of the target/distance you are using isnt quite right.

    The other thing that can cause misses, is the projectile velocity isnt great enough to make the full distance you are trying to cover.
     
    touficul_Islam likes this.
  8. SovietSpartan

    SovietSpartan

    Joined:
    May 2, 2014
    Posts:
    17
    Just got it working, haha.
    It seems that the way i was rotating the object was not the right one.
    In my game i need the character to look at a Game Object so that it can point. So i have another object parented to my character that calculates the firing angle and spawns an empty in its forward. I had to change the empty's Z axis position to like 20000 and now my character points almost perfectly to the right angle.

    Aside from that i also needed my angle calculator to look at, at the same time, to the ending position of the projectile (which is where the raycast from the crosshair collides with something).

    Here's the code in case anyone needs something like this in the future:

    Code (CSharp):
    1.     public Vector3 endPos;
    2.     public Vector3 startPos;
    3.     public float speed;
    4.     public float distance;
    5.  
    6. void Update(){
    7.  
    8.         float dist = Vector3.Distance (startPos, endPos);
    9.         distance = dist;
    10.  
    11. //Here we assign the rotation
    12.             Vector3 relativePos = endPos - transform.position;
    13.             Quaternion rotation = Quaternion.LookRotation(relativePos);
    14.             transform.rotation = rotation;
    15.             var tempRot = transform.eulerAngles;
    16.  
    17.                        //This line of code is so that we can point torwards the target position, while also pointing to the                            firing angle
    18.             tempRot.x = transform.eulerAngles.x-getAngle();
    19.             transform.eulerAngles = tempRot;
    20. }
    21. //Here we get the angle
    22.     float getAngle(){
    23.         float gravity = 9.81f;
    24.         float angle = 0.5f*(Mathf.Asin ((gravity * distance) / (speed*speed)));
    25.         return angle*Mathf.Rad2Deg;
    26.      
    27.     }
     
    Last edited: Dec 16, 2015
  9. Panthesilea

    Panthesilea

    Joined:
    May 31, 2013
    Posts:
    13
    Is it possible to calculate the target angle when surface is like a sphere and it has a gravity center?
     
    acbucha likes this.
  10. touficul_Islam

    touficul_Islam

    Joined:
    May 30, 2020
    Posts:
    1
    Thank man it really helped
     
  11. valentin56610

    valentin56610

    Joined:
    Jan 22, 2019
    Posts:
    156
    So, same for me, as long as both tanks are on the same height it's all good trajectory is fine, but if one of them is above or under the other it gets completely wrong

    @JamesLeeNZ said height didn't have any impact but it seems to have one

    Here's what I'm using :
    Code (CSharp):
    1. angle = 0.5f * (Mathf.Asin((Physics.gravity.y * Vector3.Distance(from, to)) / (speed * speed)) * Mathf.Rad2Deg);
    I forgot to mention that the orientation of the body also has to be taken into account, as my tank that's going down a 10 degrees hill is tilted 10 degrees on the X, the angle that the formula gives me is something like 0.6
    Somehow I need to combine it to the tank's orientation? I tried but adding the tank's Euler X to the angle value still didn't give an okay result
    Everything is still off by quite a bit.
    My tanks are about 2 km away from each other