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
0
Question by Alex_Gray · Aug 06, 2012 at 02:01 AM · aimtower defense

Formula to calculate a position to fire at?

Edit: Is there a formula that calculates the position a bullet would meet an enemy depending on the bullet's speed and the enemy's speed and direction?

In example: Let's take a 2-dimensional grid (x,y) and there is a tower at (1,1) and a enemy at (4,2), the enemy lies within the tower's range so the tower fires a bullet. The bullet travels at a speed of 3 (Units/Sec). The enemy is traveling at a speed of 2 (Units/Sec) at a 52 degree angle... Where would the tower have to shoot the bullet in order to hit the enemy at it's current velocity, while taking into consideration the bullet's speed?

Comment
Add comment
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

6 Replies

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

Answer by Bunny83 · Aug 11, 2012 at 02:46 AM

Ok, I finally converted my CalculateInterceptCourse function from c++ to c#, simplified it a bit and fixed a problem so it always picks the best course when there are two available.

 public static Vector3 CalculateInterceptCourse(Vector3 aTargetPos, Vector3 aTargetSpeed, Vector3 aInterceptorPos, float aInterceptorSpeed)
 {
     Vector3 targetDir = aTargetPos - aInterceptorPos;

     float iSpeed2 = aInterceptorSpeed * aInterceptorSpeed;
     float tSpeed2 = aTargetSpeed.sqrMagnitude;
     float fDot1 = Vector3.Dot(targetDir, aTargetSpeed);
     float targetDist2 = targetDir.sqrMagnitude;
     float d = (fDot1 * fDot1) - targetDist2 * (tSpeed2 - iSpeed2);
     if (d < 0.1f)  // negative == no possible course because the interceptor isn't fast enough
         return Vector3.zero;
     float sqrt = Mathf.Sqrt(d);
     float S1 = (-fDot1 - sqrt) / targetDist2;
     float S2 = (-fDot1 + sqrt) / targetDist2;

     if (S1 < 0.0001f)
     {
         if (S2 < 0.0001f)
             return Vector3.zero;
         else
             return (S2) * targetDir + aTargetSpeed;
     }
     else if (S2 < 0.0001f)
         return (S1) * targetDir + aTargetSpeed;
     else if (S1 < S2)
         return (S2) * targetDir + aTargetSpeed;
     else
         return (S1) * targetDir + aTargetSpeed;
 }

Additionally here's another function which might be useful: FindClosestPointOfApproach

 public static float FindClosestPointOfApproach(Vector3 aPos1, Vector3 aSpeed1, Vector3 aPos2, Vector3 aSpeed2)
 {
     Vector3 PVec = aPos1 - aPos2;
     Vector3 SVec = aSpeed1 - aSpeed2;
     float d = SVec.sqrMagnitude;
     // if d is 0 then the distance between Pos1 and Pos2 is never changing
     // so there is no point of closest approach... return 0
     // 0 means the closest approach is now!
     if (d >= -0.0001f && d <= 0.0002f)
         return 0.0f;
     return (-Vector3.Dot(PVec, SVec) / d);
 }

I've made a small test application which shows the difference between the "true" interception point / course and the approximation of cassius. You can change the speed of the target and the speed of your bullet. When you have at least a 5 times higher bulletspeed the result of the simple prediction is enough.

Usually the speeds don't differ that much. In Quakelife for example the player's runspeed is 320 and the rocketspeed is 1000 --> x3.125 The original Quake3 had even less: rocketspeed 800 --> x2.5 On top of that in Quake it's possible to move even faster than the rocket can fly ;)

edit
I've exported a package of the sample application. The script is quite messy. Most stuff is just there for the visualization or to distinguish the two different methods ;)

Comment
Add comment · Show 4 · 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 Alex_Gray · Aug 13, 2012 at 07:38 PM 0
Share

I like your application, and I also want to mention, u shouldn't worry about the path direction changing, because it moves in a straight line from waypoint to waypoint... so it will work! But I have a question about the code... I can't get it to work... I've never dealt with creating a Vector3 that takes arguments... how do I do it, I keep getting an error

avatar image Alex_Gray · Aug 13, 2012 at 09:44 PM 0
Share

It's not working the way it did on your application :(

Edit: Do you think you'd be able to upload your project so I can see how you set everything up please?

avatar image Bunny83 · Aug 14, 2012 at 02:05 AM 0
Share

I've edited my answer and added a package which contains the sample scene. Good luck ;)

avatar image cassius · Aug 14, 2012 at 02:23 PM 0
Share

@Bunny83 Right-on. I see what you're saying about this script vs $$anonymous$$e. I guess the way my game works the shots are always accurate, but I can clearly see in your example why it wouldn't have worked for the OPs needs.

avatar image
1

Answer by mouurusai · Aug 11, 2012 at 06:39 AM

http://wiki.unity3d.com/index.php/Calculating_Lead_For_Projectiles

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 Seth-Bergman · Aug 06, 2012 at 06:50 AM

 void CalculateAimPos(Vector3 targetPos, Quaternion targetRot, int targetSpeed, Vector3 myPos)
  {
 Vector3 aimPos = (targetPos + myPos) * .9;
 desiredRotation = Quaternion.LookRotation(aimPos);
  }

I believe it's as simple as that

of course as far as I can see here you are not passing the (aimPos) to the bullet yet, to know where to end up.. I assume you are planning this..

Bigger problem though, is that all your declarations are in javascript! but this looks to be a c# script.. to declare your vars, change it to:

  Vector3 targetPos = myTarget.position;
  //Find target's rotation
  Quaternion targetRot = Quaternion.LookRotation (myTarget.position - transform.position, Vector3.up);
  //Find target's speed
  int targetSpeed = (int) myTarget.gameObject.GetComponent().mySpeed;
  //Find tower's position
  Vector3 myPos = transform.position;

hope this helps

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 Alex_Gray · Aug 08, 2012 at 11:50 PM 0
Share

Yes I changed all of the "var" but the problem with the first part:

void CalculateAimPos(Vector3 targetPos, Quaternion targetRot, int targetSpeed, Vector3 myPos)

{ Vector3 aimPos = (targetPos + myPos) * .9; desiredRotation = Quaternion.LookRotation(aimPos); } well first off it'd be (targetPos - myPos), but the enemy has a set speed, so if it went higher, the bullet wouldn't hit the enemy on time... and the bullet has a speed that can change as well. so what I'm asking is there a formula to find the Postion an enemy will be at given it's own speed and direction while also taking in consideration the bullet's speed?
avatar image
0

Answer by cassius · Aug 09, 2012 at 12:11 AM

Actually I wrote a script that does almost exactly what you want. Unity3D Enemy AI Script to Anticipate Player’s Future Position. Basically it will calculate the player's speed (though you could change it to whatever) and takes into account the speed of the enemy's bullet. It then shoots the bullet towards where the player would be once the bullet reaches that distance.

I'm sure it can be streamlined better but hope it helps. It's javascript.

Comment
Add comment · Show 5 · 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 Alex_Gray · Aug 10, 2012 at 01:04 AM 0
Share

Well that sounds like what I am looking for, of course it's the opposite way :) but that shouldn't be a problem, and I use C# but I'm sure I can recode it! I'll check it out!

avatar image Alex_Gray · Aug 10, 2012 at 01:42 AM 0
Share

Unfortuantly, I couldn't use it... It would work if it moved in straight line, but it won't help to calculate it's movement on a 2D grid :( I can't figure out the part that was left out... I'm still trying to find the right formula

avatar image Bunny83 · Aug 10, 2012 at 02:23 AM 0
Share

@cassius: This is actually very inaccurate. When the bullet is very fast it's almost neglectable, but when they move at around the same speed or just 2 or 3 times different it might get very inaccurate depending on the angle.

@$$anonymous$$_Gray: What do you mean by not in a straight line? Do you mean you have a tower defence game and an arbitrary path the enemies will follow? in this case it's almost impossible to create a formula that calculates this. In such a case it's really better to use something like cassius said, but with two changes:

  • You need to be able to calculate the position of the enemy at a specific time in the future.

  • You have to use an iterative approach.

So you calculate the distance to the target and then you get the time the bullet would take. now move the enemy ahead of time to the position it will be after that time and then repeat.

Each iteration it will get closer to the real interception point.


If your enemy moves in one direction, you can calculate an interception course. I've written such a function a while ago in C++ and wasn't in need to convert it to C#. If you're interested i can convert it, or do it yourself ;)

Actually I shouldn't post the code it since it's the evil code that enables bot programmers to create aimbots for projectile weapons like rocket launchers ;)

avatar image cassius · Aug 10, 2012 at 04:55 PM 0
Share

@Bunny83: I'm not sure what you mean by my script beco$$anonymous$$g inaccurate. It works 100% of the time in my game exactly as expected. But of course understanding that $$anonymous$$_Gray is looking for something that changes direction, I think you're right that it's almost impossible to write a formula for.

Wouldn't the iterative approach you mentioned basically result in a heat-seeking missile-style action? Or maybe that's what $$anonymous$$_Gray is actually after?

avatar image Bunny83 · Aug 10, 2012 at 11:56 PM 0
Share

@cassius: Your method is never 100% correct, sorry ;) You calculate time you need to the target from the actual position of you and of the target, but the time until you reach the target can be more or less than that depending on if the object moves away or comes closer.

Your approach will improve when you do your steps multiple times.

Again, if the speed difference is big (so the projectile is times faster than the enemy) the error is almost neglectable, but when it's just double the speed or less your method fails. I've made an example. I will post an answer myself. It just takes some more time ;)

avatar image
0

Answer by PoyrazGoksel · Mar 08, 2020 at 03:55 AM

This is what i did using simple maths and physics end result is 100% precise

     /// <summary>
     /// <para>Since Laser speed is constant no need to calculate relative speed of laser to get interception pos!</para>
     /// <para>Calculates interception point between two moving objects where chaser speed is known but chaser vector is not known(Angle to fire at * LaserSpeed"*Sort of*")</para>
     /// <para>Can use System.Math and doubles to make this formula NASA like precision.</para>
     /// </summary>
     /// <param name="PC">Turret position</param>
     /// <param name="SC">Speed of laser</param>
     /// <param name="PR">Target initial position</param>
     /// <param name="VR">Target velocity vector</param>
     /// <returns>Interception Point as World Position</returns>
     public Vector3 CalculateInterceptionPoint3D(Vector3 PC, float SC, Vector3 PR, Vector3 VR)
     {
         //! Distance between turret and target
         Vector3 D = PC - PR;
 
         //! Scale of distance vector
         float d = D.magnitude;
 
         //! Speed of target scale of VR
         float SR = VR.magnitude;
 
         //% Quadratic EQUATION members = (ax)^2 + bx + c = 0
 
         float a = Mathf.Pow(SC, 2) - Mathf.Pow(SR, 2);
 
         float b = 2 * Vector3.Dot(D, VR);
 
         float c = -Vector3.Dot(D, D);
 
         if ((Mathf.Pow(b, 2) - (4 * (a * c))) < 0) //% The QUADRATIC FORMULA will not return a real number because sqrt(-value) is not a real number thus no interception
         {
             return Vector2.zero;//TODO: HERE, PREVENT TURRET FROM FIRING LASERS INSTEAD OF MAKING LASERS FIRE AT ZERO!
         }
         //% Quadratic FORMULA = x = (  -b+sqrt( ((b)^2) * 4*a*c )  ) / 2a
         float t = (-(b) + Mathf.Sqrt(Mathf.Pow(b, 2) - (4 * (a * c)))) / (2 * a);//% x = time to reach interception point which is = t
 
         //% Calculate point of interception as vector from calculating distance between target and interception by t * VelocityVector
         return ((t * VR) + PR);
     }
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 Haugen · Apr 05, 2021 at 01:46 PM 0
Share

This is almost perfect. But firing a bullet with a rigidbody and a velocity applied, (zero mass, no gravity and zero drag), will result in a miss. If I do about 20% of speed, it's better, but it still misses quite a lot. I have debugged this using rays, and placing a red dot on the aimpoint, and it aims exactly at the point.

There might be some Unity physics shenanigans involved here, but the math here should be perfect, and it's reasonably performant

  • 1
  • 2
  • ›

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

15 People are following this question.

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

Related Questions

facing direction that does not return to zero 1 Answer

Aim to crosshair? 3 Answers

Bow Aim Y Axis (Up and Down) 1 Answer

Crosshair Aiming Issue, Simple, Yet Confusing. 1 Answer

Aim at touch (2D). 2 Answers


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