Search Unity

Predic future position of enemy and where bullet will be to hit 100% of the time.

Discussion in 'Scripting' started by Ziron999, Oct 8, 2015.

  1. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    Here is a screenshot of what I'm trying to accomplish:

    I do not want to use the built in unity movetowards or anything like that. this is a pure c# formula question. How would I detect this without using help from unity. The reason why is because unity turns the bullets with movetowards which is not what I want...the bullet needs to remain straight and impact the target's position it's moving towards.

    It is a prediction formula I'm looking for and it's pretty basic but I'm so use to just cheating and using stuff like vector3.movetowards that I'm not really sure how to do this.

    What I've figured out so far is I will need to do something like this...

    Code (CSharp):
    1. Vector3 newTargetPos = targetObject.Position* targetObject.Velocity;
    2. Vector3 newPlayerPos = player.Position* player.Velocity;
    and then shoot with newTargetPos + newPlayerPos

    but what's the rest of the formula? how do I do the rest? bulletspeed would be used somehow in this right?
    I never get any answers on unity answers so figured it'd ask here lol...
     
  2. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    You're mixing up an algorithm to move an object in a straight line, versus an algorithm to calculate where 2 lines would intersect.

    If you want the second, well you need to start with what unknown variable are you calculating for, and what values are known and/or constants.

    For example, the thing you're trying to shoot is moving from some position in some direction and some speed. These are knowns that can't be changed.

    The projectile you shoot is probably also a constant, and therefore known.

    Where as the position you shoot from, the speed you can move to that position at, the time you shoot at, and the direction you shoot in are all unknowns.

    And the thing is, the more unknowns, the harder it is to calculate, since there can be an infinite number of answers to resolve a system with 2 or more unknowns. So usually you calculate with 1 unknown... just like a sniper will lay down and not move and reduce all unknowns (wind velocity, etc) and then just shoot in a specific direction (1 variable) to increase accuracy of strike.

    Well you need to do the same thing. You need to decide what unknowns you'll force to knowns (stop moving and stand still to shoot), to reduce unknowns to 1 or 2.

    And even then there's no guarantee. You could stop movement and end up behind a wall, and therefore unable to shoot.
     
    Last edited: Oct 8, 2015
  4. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    for the target the knowns are:
    velocity & position
    projectile knowns are:
    speed
    player knowns are:
    velocity & position
    so your saying I would have to do to many calculations with this much information and there is no real simple way to do it?
    Walls would not matter in this equation btw that whole thing can be ignored.
    Think of it as an automated targeting asteroids game.
     
  5. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    I have converted the information james has given as follows:
    Code (CSharp):
    1. static float sqrMagnitude(Vector3 v3)
    2.         {
    3.             float temp = (float)Math.Sqrt(v3.X * v3.X + v3.Y * v3.Y + v3.Z * v3.Z);
    4.             return temp;
    5.         }
    6.  
    7.         static float magnitude(Vector3 v3)
    8.         {
    9.             float temp = v3.X * v3.X + v3.Y * v3.Y + v3.Z * v3.Z;
    10.             return temp;
    11.         }
    12.  
    13.         //first-order intercept using absolute target position
    14.         public static Vector3 FirstOrderIntercept
    15.         (
    16.             Vector3 shooterPosition,
    17.             Vector3 shooterVelocity,
    18.             float shotSpeed,
    19.             Vector3 targetPosition,
    20.             Vector3 targetVelocity
    21.         )
    22.         {
    23.             Vector3 targetRelativePosition = targetPosition - shooterPosition;
    24.             Vector3 targetRelativeVelocity = targetVelocity - shooterVelocity;
    25.             float t = FirstOrderInterceptTime
    26.             (
    27.                 shotSpeed,
    28.                 targetRelativePosition,
    29.                 targetRelativeVelocity
    30.             );
    31.             return targetPosition + t * (targetRelativeVelocity);
    32.         }
    33.         //first-order intercept using relative target position
    34.         public static float FirstOrderInterceptTime
    35.         (
    36.             float shotSpeed,
    37.             Vector3 targetRelativePosition,
    38.             Vector3 targetRelativeVelocity
    39.         )
    40.         {
    41.             float velocitySquared = magnitude(targetRelativeVelocity);
    42.             if (velocitySquared < 0.001f)
    43.                 return 0f;
    44.  
    45.             float a = velocitySquared - shotSpeed * shotSpeed;
    46.  
    47.             //handle similar velocities
    48.             if (Math.Abs(a) < 0.001f)
    49.             {
    50.                 float t = -magnitude(targetRelativePosition) /
    51.                 (
    52.                     2f * Vector3.Dot
    53.                     (
    54.                         targetRelativeVelocity,
    55.                         targetRelativePosition
    56.                     )
    57.                 );
    58.                 return Math.Max(t, 0f); //don't shoot back in time
    59.             }
    60.  
    61.             float b = 2f * Vector3.Dot(targetRelativeVelocity, targetRelativePosition);
    62.             float c = magnitude(targetRelativePosition);
    63.             float determinant = b * b - 4f * a * c;
    64.  
    65.             if (determinant > 0f)
    66.             { //determinant > 0; two intercept paths (most common)
    67.                 float t1 = (-b + (float)Math.Sqrt(determinant)) / (2f * a),
    68.                         t2 = (-b - (float)Math.Sqrt(determinant)) / (2f * a);
    69.                 if (t1 > 0f)
    70.                 {
    71.                     if (t2 > 0f)
    72.                         return Math.Min(t1, t2); //both are positive
    73.                     else
    74.                         return t1; //only t1 is positive
    75.                 }
    76.                 else
    77.                     return Math.Max(t2, 0f); //don't shoot back in time
    78.             }
    79.             else if (determinant < 0f) //determinant < 0; no intercept path
    80.                 return 0f;
    81.             else //determinant = 0; one intercept path, pretty much never happens
    82.                 return Math.Max(-b / (2f * a), 0f); //don't shoot back in time
    83.         }
    However I'm not sure how unity does sqrmagnitude I think it's wrong because it is only semi working.
     
    Last edited: Oct 8, 2015
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    magnitude is:

    sqrt(x^2 + y^2 + z^2)

    sqrMagnitude is just the same thing with out the sqrt, because sqrt is expensive.

    x^2 + y^2 + z^2
     
  7. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    ah so I wrote them backwards lol ok easy enough fixed these 2:
    Code (CSharp):
    1. static float sqrMagnitude(Vector3 v3)
    2.         {
    3.             float temp = (float)(Math.Pow(v3.X, 2) + Math.Pow(v3.Y, 2) + Math.Pow(v3.Z, 2));
    4.             return temp;
    5.         }
    6.  
    7.         static float magnitude(Vector3 v3)
    8.         {
    9.             float temp = (float)Math.Sqrt(Math.Pow(v3.X, 2) + Math.Pow(v3.Y, 2) + Math.Pow(v3.Z, 2));
    10.             return temp;
    11.         }
    However this is just a performance change more then anything good change though!

    EDIT: fixed the power calculation
     
    Last edited: Oct 8, 2015
  8. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    It does work while standing still now! but when moving something is being calculated wrong :(
     
  9. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
  10. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    There is no arc's or bullet drop so trajectory shouldn't need to apply does it?
     
  11. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    trajectory still applies, it's just linear instead of curved.

    Trajectory is just the path of a moving projectile through space. Your projectile just doesn't have gravity effecting it.
     
  12. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    Ah I've always thought of trajectory as gravity being involved guess I'll look into it. Thing is, it does work if the ship stays still now which makes me think it is just an issue with that interception math when the player is moving.

    EDIT: after just reading the very start of what james posted:
    "the ballistic trajectory of a projectile is the path that a thrown or launched projectile or missile will take under the action of gravity"
    it does involve gravity if you go into trajectory?
     
  13. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    Ok. So I assumed that you are using a rigidbody driven projectile. Instantiate, AddForce in correct direction, let it fly. Is this correct? Or are you doing your projectile movement some other way?

    The first algorithm doesn't care about gravity. Its solely about predicting a future position based on projectile velocity and target velocity. It is accurate assuming the target follows a constant vector/speed (straight line). If the target is say flying in a circle, it will likely miss. Not much you can do about that.

    The second algorithm is what accounts for bullet drop. It will calculate how much additional angle you need to add based on gravity, velocity, and distance. If your projectiles are not using gravity, you wont need this.

    Also make sure your projectile drag settings are 0. Any drag will change the velocity making your projectiles miss. You can account for that with extra algorithms, but tbh, its not worth the effort/calculate. Just turn off drag. Make your life easy.
     
  14. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    nah It shoots in a direction based on this vector3. y is not used since it's 2d.

    The easiest way I can think of to describe this is if you want AI to try and shoot ahead of you if you try to strafe left or right. The AI needs to predict where you are moving and how far ahead they predict essentially determines the AI's accuracy.
     
    Last edited: Oct 8, 2015
  15. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    What you are talking about is impossible. You cant hit an unpredictable target. If the player moves left/right constantly with no consistency there is no way of accurately predicting where the player will be.

    What sort of distances are we talking about? If its 2d, you can probably get rid of the prediction and use angle of reach solely if the distances are close (less than 100 units). This is dependent on the velocity of your projectile. If its slow, you have no chance of prediction.

    Also, how are you moving your player?