Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
11
Question by Patyrn · Feb 24, 2011 at 09:10 AM · javascriptmathprojectiletrajectory

Trajectory of a projectile formula. Does anyone know maths?

I found this handy page on wikipedia: http://en.wikipedia.org/wiki/Trajectory_of_a_projectile

In there is this formula:

To hit a target at range x and altitude y when fired from (0,0) and with initial velocity v the required angle(s) of launch are:

alt text

I gave it my best shot trying to convert this to code, but frankly it's way beyond my math abilities. It sort of works at long ranges, then goes crazy at short ranges. Here's my wack at it:

 function CalculateProjectileFiringSolution2 ()
 {
     var targetTransform =  target.transform.position;
     var barrelTransform = barrel.transform.position;
     var y = targetTransform.y - barrelTransform.y;
     targetTransform.y = barrelTransform.y = 0;
     var x = (targetTransform - barrelTransform).magnitude;
     var v = projectileSpeed;
     var g = Physics.gravity.y;
     var sqrt = (v*v*v*v) - (g * (g * (x*x) + 2 * y * (v*v)));
     if (sqrt<0) {
         Debug.Log("No Solution");
         return 0;
     }
     sqrt = Mathf.Sqrt(sqrt);
     var calculatedAnglePos = Mathf.Atan(((v*v) + sqrt) / (g*x));
     var calculatedAngleNeg = Mathf.Atan(((v*v) - sqrt) / (g*x));    
     return calculatedAnglePos * Mathf.Rad2Deg;
 }

Can anyone help me out?

EDIT: Updated per suggestions. EDIT AGAIN: Works now.

Comment
Add comment · Show 6
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Feb 25, 2011 at 07:52 PM 1
Share

You could or even should use Atan2. It's a bit saver and calculates the right quadrant (returns a value between [-Pi,Pi] ). Take a look at http://en.wikipedia.org/wiki/Atan2 And of course: http://unity3d.com/support/documentation/ScriptReference/$$anonymous$$athf.Atan2.html

avatar image Patyrn · Feb 25, 2011 at 08:04 PM 1
Share

Not sure what to plug into atan2. I only have one value.

avatar image Gabriel 1 · Mar 14, 2011 at 07:46 PM 1
Share

Can you maybe put up your final code for those searching for a similar solution?

avatar image Patyrn · Mar 14, 2011 at 11:53 PM 1
Share

Sorry, I edited the question with the working code but that was probably somewhat unclear. I answered with my most up-to-date code including the other functions I ended up needing.

avatar image superp · Feb 10, 2014 at 03:10 AM 0
Share

i am having problem getting above function work. can someone help? I posted a separate question here http://answers.unity3d.com/questions/633171/trajectory-of-a-projectile-formula-get-the-same.html

Show more comments

5 Replies

· Add your reply
  • Sort: 
avatar image
7
Best Answer

Answer by taoa · Feb 24, 2011 at 10:22 AM

This formula considers you shoot your projectile from (0,0), which means in your case that you must subtract your barrel position from your target position:

var y = targetTransform.y - barrelTransform.y; var x = targetTransform.x - barrelTransform.x;

Also, for the love of all that's worthy, do not EVER use Mathf.Pow(n,2) when all you want to do is n*n! Pow is a powerful (bwahaha) function that can take a float value as a second parameter, don't waste it on integer powers, as it's way more expensive that a n*n (even a n*n*n*n*n...).

If to_sqrt is <0 before processing it's square root, then it means there is no solution with real numbers, the velocity is insufficient to reach the desired position, so your gameplay code must handle that situation somehow (start at least with a Debug.Log). But do that BEFORE you carry on with your calculation of the angle. You can now drop the Mathf.Abs() part of Mathf.Sqrt(Mathf.Abs(to_sqrt)).

You don't handle the +/- part of the equation properly: there is either 0 (we covered it), 1 (special case where the use or + or - doesn't matter, same result), or two possible solutions to this equation, each given by using either + or -. They will both be correct, so it's up to you to choose which one. I suggest you toss a coin. Or you could simulate one, see if your projectile hits something on the way, then choose the other one if it's better. Your call.

The rest of your code seems fine to me. Except calculatedAngle * 90.0f. I have no idea what the hell you're trying to do here ^^

Best of luck!

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Patyrn · Feb 24, 2011 at 08:19 PM 1
Share

Thanks for the response. I updated per your suggestions but it still isn't working. The numbers it returns are in the area of +- 2 or lower so it's always pointing almost exactly straight ahead, regardless of projectile speed.

avatar image Patyrn · Feb 24, 2011 at 09:26 PM 1
Share

Never$$anonymous$$d. Atan returns radians. I knew it would be something stupid. Thanks again for all your help. :)

avatar image superp · Feb 13, 2014 at 01:48 AM 0
Share

i am having problem getting above function work. can someone help? I posted a separate question here http://answers.unity3d.com/questions/633171/trajectory-of-a-projectile-formula-get-the-same.html do you know why this is happening?

avatar image
3

Answer by Patyrn · Mar 14, 2011 at 11:52 PM

As requested the final code I'm using for my projectile stuff:

 float CalculateMaximumRange ()
 {
     float g = Physics.gravity.y;
     float y = origin.position.y;
     float v = projectileSpeed;
     float a = 45 * Mathf.Deg2Rad;
     float vSin = v * Mathf.Cos(a);
     float vCos = v * Mathf.Sin(a);
     float sqrt = Mathf.Sqrt(vSin * vSin + 2 * g * y);
     return Mathf.Abs((vSin / g) * (vCos + sqrt));
 }

 float CalculateProjectileFiringSolution ()
 {
     Vector3 targetTransform =  target.position;
     Vector3 barrelTransform = gunMuzzlePoint.position;
     float y = barrelTransform.y - targetTransform.y;
     targetTransform.y = barrelTransform.y = 0;
     float x = (targetTransform - barrelTransform).magnitude;
     float v = projectileSpeed;
     float g = Physics.gravity.y;
     float sqrt = (v*v*v*v) - (g * (g * (x*x) + 2 * y * (v*v)));
     // Not enough range
     if( sqrt<0 )
     {
         haveFiringSolution = false;
         return 0.0f;
     }
     haveFiringSolution = true;
     sqrt = Mathf.Sqrt(sqrt);
     // DirectFire chooses the low trajectory, otherwise high trajectory.
     if (directFire) return Mathf.Atan(((v*v) - sqrt) / (g*x));
     else return Mathf.Atan(((v*v) + sqrt) / (g*x));
 }

 float CalculateFlightTime ( float angle )
 {
     Vector3 targetTransform =  target.position;
     Vector3 barrelTransform = gunMuzzlePoint.position;
     float x = (targetTransform - barrelTransform).magnitude;
     float v = projectileSpeed;
     angle = angle == 0 ? 45 : angle;
     float time = x / (v * Mathf.Cos(angle * Mathf.Deg2Rad));
     return time * .7f;
 }


Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kiada · Dec 12, 2012 at 01:30 PM 0
Share

Sorry for being a bit dim, but once you have all 3 floats from the methods - how do you use the values to gain motion? I couldn't find a simple enough equation on the wiki page to piece it all together! Thanks for posting the code though!

avatar image
2

Answer by petrucio · Jul 03, 2019 at 04:03 AM

Putting it all together with proper formatting, less noise, and @Arowx 's fix:


 bool CalculateThrowAngle(Vector3 from, Vector3 to, float speed, out float angle)
 {
     float xx = to.x - from.x;
     float xz = to.z - from.z;
     float x = Mathf.Sqrt(xx * xx + xz * xz);

     float y = from.y - to.y;
     
     float v = speed;
     float g = Physics.gravity.y;
     
     float sqrt = (v*v*v*v) - (g * (g * (x*x) + 2 * y * (v*v)));
     
     // Not enough range
     if (sqrt < 0)
     {
         angle = 0.0f;
         return false;
     }
     
     angle = Mathf.Atan(((v*v) - Mathf.Sqrt(sqrt)) / (g*x));
     return true;
 }


Usage:

     float throwAngle;
     if (CalculateThrowAngle(thing.position, at.position, maxSpeed, out throwAngle))
     {
         Vector3 throwDirection = (at.position - thing.position);
         throwDirection.y = 0;
         throwDirection = Vector3.RotateTowards(throwDirection, Vector3.up, throwAngle, throwAngle).normalized;
     }

     rigidbody.velocity = throwDirection * maxSpeed;


In action:

alt text

(yellow = line to target, red = calculated throw direction, green = path taken. Falls a tiny bit short because of drag, which is fine in my case)

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by Arowx · Dec 11, 2012 at 10:00 PM

Minor correction you are calculating the value x as the magnitude of the vector this will only give accurate results when the height difference is near zero.

You need to calculate x as the horizontal distance only e.g.

        float y = (barrelTransform.y - targetTransform.y);
 
         //targetTransform.y = barrelTransform.y = 0;
 
         float xx = targetTransform.x - barrelTransform.x;
         float xz = targetTransform.z - barrelTransform.z;
         float x = Mathf.Sqrt(xx * xx + xz * xz);
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by valentin56610 · Jan 19 at 09:52 AM

I would like to take a second to say that @petrucio 's solution didn't really work for me, there was stuff missing before returning the angle. First, the results were in radians and not in real degrees, so I did the conversion from radians to degrees, and I also fixed the results that were wrong, this is ready to be used in your game as long as you use EulerAngles. So here is the final working version:

     public static bool CalculateThrowAngle(Vector3 from, Vector3 to, float speed, out float angle)
     {
         float xx = to.x - from.x;
         float xz = to.z - from.z;
         float x = Mathf.Sqrt(xx * xx + xz * xz);
         float y = from.y - to.y;
 
         float v = speed;
         float g = Physics.gravity.y;
 
         float sqrt = (v * v * v * v) - (g * (g * (x * x) + 2 * y * (v * v)));
 
         // Not enough range
         if (sqrt < 0)
         {
             angle = 0.0f;
             return false;
         }
 
         angle = Mathf.Atan(((v * v) + Mathf.Sqrt(sqrt)) / (g * x));
         angle = (angle * 360) / (float)(2 * Math.PI); // Conversion from radian to degrees
         angle = 90 + angle; // Idk why but thats needed
         angle *= -1; // Unity negative is upward, positive is pointing downard
         return true;
     }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

6 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Distance in a Trajectory of a projectile 0 Answers

Top down shooter trajectory 1 Answer

Unity Exponentiation question. 1 Answer

Question about FPS and Raycasting Javascript 2 Answers

Move speed not working properly 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges