Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How might one lerp between direction vectors?

Discussion in 'Scripting' started by MonkeyPuzzle, Jun 11, 2023.

  1. MonkeyPuzzle

    MonkeyPuzzle

    Joined:
    Jan 17, 2016
    Posts:
    117
    I wan to have a player shoot a missile, and have it start in the direction that the player is facing (forward) then smoothly change direction to target an enemy.

    Is there a way to lerp between direction vectors?

    Any help is appreciated.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Yes... yes there is, but it's a little bit subtle.

    What you describe that you want isn't really lerping between vectors (which is TOTALLY doable btw! See bottom of this post...) but rather changing your angular heading to home in on a different target at a different direction.

    Enclosed is a "Missile Turn Towards" microgame.

    The relevant part doing the steering is this snippet. See attached package for full script and setup.

    Code (csharp):
    1.     private void UpdateMissile()
    2.     {
    3.         // cartesian distance to player
    4.         Vector3 delta = Player.transform.position - Missile.transform.position;
    5.  
    6.         // what heading is that?
    7.         float DesiredHeadingToPlayer = Mathf.Atan2(delta.y, delta.x) * Mathf.Rad2Deg;
    8.  
    9.         // are we good enough?
    10.         float AngleError = Mathf.DeltaAngle(DesiredHeadingToPlayer, CurrentMissileHeading);
    11.  
    12.         // nope, then turn!
    13.         if (Mathf.Abs( AngleError) > AcceptableAngleError)
    14.         {
    15.             CurrentMissileHeading = Mathf.MoveTowardsAngle(CurrentMissileHeading, DesiredHeadingToPlayer, MissileTurnRate * Time.deltaTime);
    16.         }
    17.  
    18.         // missile gets more agile (turns faster)
    19.         MissileTurnRate += MissileTurnRateIncrease * Time.deltaTime;
    20.  
    21.         // missile turns
    22.         Missile.transform.rotation = Quaternion.Euler(0, 0, CurrentMissileHeading);
    23.  
    24.         // missile gathers speed
    25.         MissileSpeed += MissileAcceleration * Time.deltaTime;
    26.  
    27.         // missile moves
    28.         Missile.transform.position += Missile.transform.right * MissileSpeed * Time.deltaTime;
    29.     }
    (Lines 19 and 25 above are just to make the game get harder over time.)

    Otherwise... if you DO just want
    Vector3.Lerp()
    , well, that's the name of the function, but I don't think it will result in a "good steer" to the missile...
     

    Attached Files:

    MonkeyPuzzle likes this.
  3. MonkeyPuzzle

    MonkeyPuzzle

    Joined:
    Jan 17, 2016
    Posts:
    117
    Thank you! This is great. I will try both options and report back.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Lerping the Vector3 could also work but it will have these weird non-linear turning artifacts, depending on how you handle the math and normalizations.

    I would just use the turning approach (obviously I did!).
     
  5. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,051
    Vector3.Slerp is here for this case, it will smoothly and linearly interpolate the direction of the vectors, avoiding non-uniformity in the turn speed.

    But yeah, a missile is a physical object and just interpolating its direction will probably be a bit stiff. Depending on what exactly you want in your case, simulating the movement of the missile discreetly, like Kurt has described, will give you much more control over the movement.
     
    Kurt-Dekker likes this.
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    I will boldly claim that Nlerp is even better! It essentially does the same thing as Slerp but much much cheaper. Given that this is only ever used to align with some orientation in space, it's really the best choice, especially if there are many missiles.

    Nlerp isn't part of the API (it is in the Mathematics package though), but it's very simple to make
    Code (csharp):
    1. static Vector3 Nlerp(Vector3 start, Vector3 end, float t)
    2.   => Vector3.Lerp(start, end, t).normalized;
    (Lerp is much faster than Slerp.)

    If slerping is still preferred, with directions it's much better to avoid Vector3.Slerp and instead do
    Code (csharp):
    1. var q = Quaternion.FromToRotation(start, end);
    and then Update with
    Code (csharp):
    1. var dir = Quaternion.Slerp(Quaternion.identity, q, t) * start;
    More information on why (and a better version of unit-vector Slerp) here.