Search Unity

Trajectory calculations!

Discussion in 'Scripting' started by MarkusDavey, Jul 29, 2011.

  1. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Hello,

    Let me put this out there first. I'm NOT a mathematician, so understanding this: is not at all within my capacity.

    So, does anyone here have any code or framework, helpful hints etc, with going about making a firing solution for a turret?

    Cheers.

    Below is the code for my projectile, it's not a physical object, so, I may have made it wrong.

    PHP:
    gravityInertia Physics.gravity Time.deltaTime;
                
    gravityInertia.Mathf.Clamp(gravityInertia.y, -21.1fMathf.Infinity);
                
                 
    transform.position transform.position transform.forward Velocity Time.deltaTime + (gravityInertia);
                
                
    lookAtPos = (transform.position transform.forward Velocity) + (Physics.gravity Time.deltaTime);
                
    transform.LookAt(lookAtPos);
     
    anycolourulike likes this.
  2. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    I'm not the best at math either.. I'd probably use iTween: see here (accurate lob). iTween is free and you could buy the accurate lob example for a dollar, if it's close to what you're looking for.
     
  3. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    without drag it would be something like this, I think:
    Code (csharp):
    1.  
    2. var initialVelocityVector : Vector3 = Vector3(100,0,0);
    3. var gravityVector: Vector3 = Vector3(0,-9.8,0);
    4. function Update()
    5. {
    6.      transform.position += (initialVelocityVector + 0.5*gravityVector*Time.deltaTime)*Time.deltaTime;
    7. }
    8.  
     
    anycolourulike likes this.
  4. flaminghairball

    flaminghairball

    Joined:
    Jun 12, 2008
    Posts:
    868
    To be clear, you're trying to lob a projectile at a specific point?
     
  5. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Correct.
     
  6. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Also, anyone else NOT getting email notifications? My spam folder is empty....
     
  7. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    I downloaded the lob project, and. I have NO idea how this works. lol.
     
  8. flaminghairball

    flaminghairball

    Joined:
    Jun 12, 2008
    Posts:
    868
    What I would do if I were you is lerp the projectile's x-z values to the desired position, and set the y position based on that. In my example below, I used the sine function to calculate y position(since it has the shape of a trajectory.
    Completely untested, my math and code might be (probably is) off.

    Code (csharp):
    1.  
    2. var speed : float = 1.0; //how fast the projectile travels
    3. var target : Transform; //what the projectile tries to hit
    4. var trajectoryHeight : float = 10.0; //the peak of the trajectory
    5.  
    6. private var startPos : Vector3; //the position we started at
    7. private var lerpPos : float = 0.0; //the lerp position we're at
    8.  
    9. function Start(){
    10.  startPos = transform.position;
    11. }
    12.  
    13. function Update(){
    14.  lerpPos = Mathf.Clamp(lerpPos + Time.deltaTime * speed, 0.0, 1.0); //lerp values need to be between 0 and 1
    15.  transform.position = Vector3.Lerp(startPos, target.position, lerpPos);
    16.  transform.position.y = trajectoryHeight *Mathf.Sin(lerpPos * Mathf.Pi); //multiplying by pi gives it a cycle of 2 - we'll only use half a cycle
    17. }
    18.  
    As said, I haven't tested that at all. It may not compile, and it may not work if it does compile. It should be enough to get you started though.
    You'll probably also want to add some damping to lerpPos so it'll slow down as it goes upwards and speed up as it goes down.

    Hope this helps.

    -Lincoln Green
     
  9. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Lerping causes the trajectory to be circular, where as real trajectory creates a parabola.

    I found this. It has a whole bunch of 'working' code at the bottom, but I have no idea how to implement it. It doesn't seem to explain itself much. Maybe I just lack the common knowledge.
     
    anycolourulike likes this.
  10. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Just to add, I'm looking for a real world simulating trajectory calculation. minus air drag.
     
  11. novashot

    novashot

    Joined:
    Dec 12, 2009
    Posts:
    373
    I cheated a bit to make a lob effect, but it works... my set up:

    my turret is set at a 45 degree angle always... but is free to rotate around...just elevation is frozen
    I have a max power setting
    Max range... at max power the round lands at max range

    I detect targets within max range... get their distance from turret
    Use the formula

    Power = 1-(distance / maxDistance)*maxPower;

    Since my elevation is always a 45... the. Projectile lobs... and the turret lowers the power put into each shot to hit pretty accuratly.

    Kind of a hack, but works for what I wanted... and fairly simple...

    If you need any code example let me know...can post later
     
  12. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    I saw this/something similar to this, on Unity Answers. Sadly, it's not too applicable to an RTS. But thanks anyway.
     
  13. novashot

    novashot

    Joined:
    Dec 12, 2009
    Posts:
    373
    In what way doesn't it work in rts? Worked fine for my top down viewed rts / tower defense prototype.
     
  14. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    Just looked on wikipedia - http://en.wikipedia.org/wiki/Trajectory_of_a_projectile#Conditions_at_an_arbitrary_distance_x
    Under - Angle θ required to hit coordinate (x,y)
    can't you just use that? And use a sensible initial velocity value.

    vel = up to you
    range = up to you
    alt = up to you

    g = gravity = 9.81

    vel2 = vel * vel
    vel4 = vel * vel * vel * vel
    dis2 = distance * distance

    num = vel2 + sqrt(vel4 - g * (g * dis2 + (2 * alt * vel2)))
    dom = g * distance
    angle = atan(num / dom)

    I think theres a few checks you have to do like it wont hit the point if the (vel4 - g * (g * dis2 + (2 * alt * vel2)))
    is negative.
     
  15. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    This is very much what I found on Unity Answers. Yet, I don't know what to do with that number now that I have it. What does it do?
     
  16. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    This outputs the angle of your barrel that fires the projectile.
     
  17. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    what's wrong with the code I gave you above?
    here is a webplayer example of it.
    right click to rotate the turret, hold left click to launch with power.
     
    Last edited: Aug 2, 2011
  18. boco

    boco

    Joined:
    Dec 7, 2010
    Posts:
    373
    why not use a parabolic equation to solve your problem that is what it was made for... Just google parabolic equation and start putting in variables to make it work...
     
  19. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    So I set the barrel's X rotation to the returned value?

    Also, ivkoni, your example is not suitable for what I'm doing, and boco, I mentioned before that I have no idea how those equations work.
     
  20. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    It is not clear from your post what you are doing.
    If you want the projectile to hit a sertain position, then you need to solve the equation for an initial velocity.
    The initial velocity is a vector with direction and magnitude. Keep one fixed and solve for the other.
     
  21. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    I updated the example to go through a point that is clicked. The longer you hold the left mouse button, the more "parabolic" the path.
    Trajectory Test
    Is this what you are trying to do?
     
    Last edited: Aug 1, 2011
  22. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    A great demo.But what I'm after is what happens in that demo, but the projectile has a static velocity. Say, the projectile goes 100m/s, and it is to hit a vector3 target.

    Is your method adaptable to that?
     
  23. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    I finally did what you said to do, instead of using a function I found that looked very much the same, and, it's okay, except it's still not hitting the target.. i'm using a rigidbody projectile that is affected by gravity, and, it seems that the function is causing the barrel to point BELOW the target.

    This is the code I am using:

    PHP:
    float CalculateProjectileFiringSolution2() 
        {
            
    //
            
    Vector3 muzzlePos barrel[0].transform.FindChild("muzzle").transform.position;
            
    //
            
    float vel projectile.GetComponent<TankProjectile>().Velocity;
            
    float range Vector3.Distance(muzzlePostarget.position);
            
    float alt = (muzzlePos.target.position.y);
            
            
    float grav 9.81f;
            
            
    float vel2 vel vel;
            
    float vel4 vel vel vel vel;
            
    float dist2 range*range;
            
            
    float sqrt Mathf.Sqrt(vel4 grav * (grav dist2 +(2alt vel2)));
            
            if (
    sqrt 0
            {
                print(
    "returning zero");
                return 
    0.0f;
            }
            
    //print(sqrt);
            
    float num vel2 sqrt;
            
    float dom grav range;
            
            
    float angle Mathf.Atan(num dom);

            return 
    angle;
        }
     
  24. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    Trajectory Test
    I used what was CrazySi said.
    The point that you target needs to be to the right of the turret, but this can be fixed. If there is no solution, (can't hit the point), I fire at 45 degrees. There are 2 solutions to the equation. Left click to use smaller angle, right click for larger one.

    Project attached, but you are probably better off to do it yourself in the general case.
     

    Attached Files:

    Last edited: Aug 2, 2011
  25. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    One more point, I'd first try using the example where time is left as a paramater and set the time to be linearly proportional to the distance to the target. This should work in any case and is the simplest solution. If it doesn't look realistic enough, then solve for the angle like CrazySi said.
     
  26. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    So, I have an issue setting the pitch of the barrel. It looks sideways, and not 'up'. And it does this no matter what I do in regards to instead of "barrel.up = firesolution()" being "barrel.right" etc etc. How would you pitch the barrel, which is a child object, and have it actually pitch upwards?
     
  27. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    Ok first of all you have the solution for the angle of the barrel. This is on a fixed axis.

    Code (csharp):
    1. // firing solution
    2.     float CalculateProjectileFiringSolution(float vel, float alt)  
    3.     {
    4.     /*
    5.     vel = up to you
    6.     range = up to you
    7.     alt = up to you
    8.    
    9.     g = gravity = 9.81
    10.    
    11.     vel2 = vel * vel
    12.     vel4 = vel * vel * vel * vel
    13.     dis2 = distance * distance
    14.        
    15.     num = vel2 + sqrt(vel4 - g * (g * dis2 + (2 * alt * vel2)))
    16.     dom = g * distance
    17.     angle = atan(num / dom)
    18.     */
    19.                
    20.     Vector2 a = new Vector2(transform.position.x, transform.position.z);
    21.     Vector2 b = new Vector2(target.position.x, target.position.z);
    22.     float dis = Vector2.Distance(a, b);
    23.        
    24.     //print("Range " + dis);
    25.        
    26.     float g = gravity;
    27.                
    28.     float dis2 = dis * dis;
    29.     float vel2 = vel * vel;
    30.     float vel4 = vel * vel * vel * vel;
    31.        
    32.     float num = vel2 + Mathf.Sqrt(vel4 - g * ((g * dis2) + (2 * alt * vel2)));
    33.     float dom = g * dis;
    34.     float angle = Mathf.Atan(num / dom);
    35.  
    36.     return angle * Mathf.Rad2Deg;
    37.     }
    In order to fire in a plane you need to transform this axis to be the direction of what you are firing at -

    Code (csharp):
    1.    
    2. // Get rotatation to face target
    3. float GetYRotation()
    4. {
    5.                Vector3 relativePos =
    6.         transform.InverseTransformPoint(target.position);                              
    7.     float x = (relativePos.x);
    8.     float z = (relativePos.z);
    9.        
    10.     float angle = Mathf.Atan2(x, z) * Mathf.Rad2Deg;
    11.        
    12.     return angle;
    13. }
    And finally to use these angles you must apply a force, this is how I do it -

    Code (csharp):
    1.            
    2. Vector3 fVector = new Vector3(force, 0, 0); // fixed vector (image a 2d trajectory graph)          
    3. Vector3 rVector = Quaternion.Euler(0, yRotation, barrelAngle) * fVector; // transformed to 3d to point at target
    4. projectile.AddRelativeForce(rVector, ForceMode.Impulse); // add force on new axis
    5.  
    All of the code is in the attached project.

    I'm sure that with the yRotation and barrelAngle you could plug these into your artillery piece orientation.
     

    Attached Files:

    Bryarey likes this.
  28. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    I also ought to point out this does not take into account wind resistance. Again refering to wiki
    http://en.wikipedia.org/wiki/Trajectory_of_a_projectile under Trajectory of a projectile with air resistance
    Air resistance is a proportional force! If you have another force acting on this object you'll have introduce a new factor for this extra force(s) being applied. I imagine that if you have a wind vector (as opposed to a more realistic vector field) you'll have to compensate the Y barrel rotation as well.
     
  29. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Still having no hope with this. I applied what you gave me in the project, and I believe I am applying the barrel angle wrong, as they REALLY like pointing 100% upright. And, the projectiles are being shot downwards at a right angle from the barrels. I'm making an example project so you can see what I mean.

    View attachment $KalvTest.zip
     
    Last edited: Aug 4, 2011
  30. boco

    boco

    Joined:
    Dec 7, 2010
    Posts:
    373
    -B +/- sqrt( B^2 - 4(a)(c)) / 2a

    this equation should solve the trajectory of the gun I would assume.. I did alot of this math in class when talking about trajectory of Cannons and Balls
     
  31. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    Theres 2 bugs I can see already, first gravity should be 9.81 not -9.81 (this will correct the - angle) and use CalculateProjectileFiringSolution to get the barrelAngle NOT GetYRotation. I ought to have named these methods, GetBarrelAngle() and GetBarrelSwivel().

    I think you also have some logic issues with rotations as well.
     
  32. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Well, I made the changes you suggested Crazy, yet the projectiles are now firing the opposite direction, and not at all towards the target. And the barrel pitch is still facing 100% upright.
     
  33. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    Ok change this line of code on 138 in TurretController.cs
    float requiredPitch = GetYRotation() * Mathf.Deg2Rad - 90f;
    to this
    float requiredPitch = CalculateProjectileFiringSolution(force, 0);

    Insert an appropriate force and do a print out of requiredPitch, you'll find its correct, theres a bug elsewhere in your code that is not rotating the barrel correctly.

    As you can see from the attached screenshot with a few tweaks I have got your project working.
    A few points aside from the above error;
    Bugs in the rotation pitch code.
    Make sure you are applying force to projectile on the correct axis.
    Correct gravity.
     

    Attached Files:

    Last edited: Aug 4, 2011
  34. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    I am hopeless at this... Truly am.

    Could you send back the project you got to work? as for me, having done what you said, am still having issues.I don't know how to apply the force correctly on the projectile, I'm setting the barrel pitch via "
    PHP:
    barrelmount[i].transform.localEulerAngles = new Vector3(CalculateProjectileFiringSolution(projectile.GetComponent<TankProjectile>().Velocitytransform.position.target.position.y)  - 90f,0);
    ", and it aims below the target.

    When you say "appropriate force", what do you mean? My projectile is to go at 100 m/s, so that is what force I put.

    Also, the higher the target, the lower it aims. I have switched around the "alt" calculation, and it still does it. I assume "alt" means altitude.....

    I corrected the gravity as well.
     
    Last edited: Aug 5, 2011
  35. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    You are getting force confused, I think. Set it to an arbitrary value, remember there are infinite firing solutions to this problem.
    I'm attaching the corrected project - plus one bug as I'm not sure how you intended this to work - you'll have to correct the barrel pitch interpolation, I just set it to snap to the correct pitch value.
     

    Attached Files:

  36. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Oooooh. I see what you've done here. But, I can't find where to switch the + - to get the gun to fire in a more direct fire solution, whilst maintaining it's 100m/s muzzle velocity.
     
  37. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    What do you mean by "more direct fire solution"? If you mean force of projectile its a global variable that you'll have to come up with a sensible way of guessing appropriate values to apply based on distance (eg barrel too high? increase force, lower barrel, etc).
     
  38. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Righto, It's just, I managed to get it to have a less crazy high parabola, but then the projectiles were flying at a snails pace. If you have not noticed, I am crap. lol.
     
  39. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    aha! I did it :)

    Here is the function now.

    PHP:
    float CalculateProjectileFiringSolution(float velfloat altVector3 muzzle)  
        { 
            
    Vector2 a = new Vector2(muzzle.xmuzzle.z);
            
    Vector2 b = new Vector2(target.position.xtarget.position.z);
            
    float dis Vector2.Distance(ab);
            
    alt = -(muzzle.target.position.y);
            
    //print("Range " + dis);
            
            
    float g Mathf.Abs(Physics.gravity.y);
                    
            
    float dis2 dis dis;
            
    float vel2 vel vel;
            
    float vel4 vel vel vel vel;
            
    float num;
            
    float sqrt vel4 * ((dis2) + (alt vel2));
            if (
    sqrt 0)
            {
                print(
    "No solution!");
                return(
    45);
            }
            
    //Direct Fire
            
    if (Vector3.Distance(muzzletarget.position) > vel 2)
                
    num vel2 Mathf.Sqrt(vel4 * ((dis2) + (alt vel2)));
            else
                
    num vel2 Mathf.Sqrt(vel4 * ((dis2) + (alt vel2)));
            
            
    float dom dis;
            
    float angle Mathf.Atan(num dom);

            return 
    angle Mathf.Rad2Deg;
        }
    Thanks very much for your help everyone, thanks especially to you Crazy. Sorry if it seemed like I was getting you to do ll the work, it's just maths was NEVER my strong suit. Than and i could never decipher all those maths symbols. If you have a key or legend, etc for those things, be sue ro let me know where to find it :p
     
    Last edited: Aug 5, 2011
  40. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    Have you tried increasing your gravity factor and force? This makes it less realistic but probably more fun to watch.
     
  41. CrazySi

    CrazySi

    Joined:
    Jun 23, 2011
    Posts:
    538
    No problem Markus, I'm sure we would all like to see the game when it is finished - good luck!
     
  42. sesobebo

    sesobebo

    Joined:
    Feb 21, 2013
    Posts:
    3
    i'm having some problems with trajectory calculations as well.
    i'm trying to send a projectile with constant velocity through the point at which i click the mouse.

    i've tried calculating the angle via the formula on wikipedia, methods from some other sites, and scripts from this thread, but the result is always the same (as it should be expected, as they all use the same equations) - the angle of my gun always seems to be too narrow, and is thus shooting projectiles below the cursor.

    here's my code if someone were kind enough to take a look at it:

    Code (csharp):
    1. #pragma strict
    2.  
    3. public var fAngle : float = 0;
    4. public var velocity : float = 40;
    5. public var bolt : GameObject;
    6.  
    7. private var vel2 : float = velocity * velocity;
    8. private var vel4 : float = velocity * velocity * velocity * velocity;
    9. private var grav : float;
    10. private var factor : float;
    11.  
    12. function Start () {
    13.  
    14.     grav = GameObject.Find ("Earth").GetComponent (EarthProperties).gravity;
    15.  
    16. }
    17.  
    18. function Update () {
    19.  
    20.     var dX : float;
    21.     var dY : float;
    22.     var c1 : float;
    23.     var c2 : float;
    24.    
    25.     var mPosition : Vector3 = Camera.main.ScreenToWorldPoint (Input.mousePosition);
    26.    
    27.     dX = mPosition.x - transform.position.x;
    28.     dY = mPosition.y - transform.position.y;
    29.     var sqrt : float = vel4 - grav * ((grav * dX * dX) + (2 * dY * vel2));
    30.    
    31.     if (sqrt < 0) {
    32.    
    33.     transform.eulerAngles = Vector3 (0, 0, 45);
    34.    
    35.     fAngle = 45;
    36.    
    37.     }
    38.    
    39.     else {
    40.        
    41.         var num : float = vel2 - Mathf.Sqrt(vel4 - grav * ((grav * dX * dX) + (2 * dY * vel2)));
    42.         var dom : float = grav * dX;
    43.         var tempAngle : float = Mathf.Atan(num / dom);
    44.        
    45.         c2 = tempAngle * Mathf.Rad2Deg;
    46.        
    47.         transform.eulerAngles = Vector3 (0, 0, c2);
    48.            
    49.         fAngle = c2;
    50.    
    51.     }
    52.    
    53.     if (Input.GetButtonDown ("Fire1")) {
    54.         FireBolt ();
    55.     }
    56.  
    57. }
    58.  
    59. function FireBolt () {
    60.  
    61.     //create bolt. the quaternion.euler stuff is for prefab pivot correction...
    62.     Instantiate (bolt, transform.position, Quaternion.Euler (0, 0, fAngle - 90));
    63.  
    64. }
    it is a bit of a grave-digging move to bring this up, but i'm running out of ideas s:

    and the whole project is in the attachmet.
     

    Attached Files:

  43. dev01

    dev01

    Joined:
    May 3, 2010
    Posts:
    21
    I'm having an issue with trying to launch of a ramp to transition to another ramp and go down the next ramp kinda like two half pipes side by side with a space in between . What's the easiest way to do this and still have physics applied? I have no idea.
     
  44. BillyMFT

    BillyMFT

    Joined:
    Mar 14, 2013
    Posts:
    178
    I think this file might be corrupt. Any chance you could reupload it?

    Thanks
     
  45. GoofBall101

    GoofBall101

    Joined:
    Jul 25, 2015
    Posts:
    57
    Ok to make all this worth it Unity just posted a tank game video on youtube. They use missile trajectory
     
  46. Bryarey

    Bryarey

    Joined:
    Aug 24, 2014
    Posts:
    25
    CrazySi, Just copy/pasted your code into my top-down view shooter (for grenade thrower), and it works perfectly! :) The only thing that I have to change is a turn value into absolute (non-negative) before doing Sqrt:

    Code (CSharp):
    1. float num = vel2 + Mathf.Sqrt( Mathf.Abs(vel4 - g * ((g * dis2) + (2 * alt * vel2))) );
    Thank you so much, you just saved me a lot of time! :)
     
  47. Dev_GTS

    Dev_GTS

    Joined:
    Mar 8, 2021
    Posts:
    5

    I have followed this tutorial, and after some changes, I achieved what I had to.