Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Math easing problem

Discussion in 'Scripting' started by ADNCG, Jul 26, 2017.

  1. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    992
    halp.png
    I have tiles on a board that need to go from whatever distance they are from 5, to 5.
    e.g. 1 goes through 2, then through 3 until 5.
    3 goes through 4 and 5.

    Currently it looks like the following bit of code.
    Code (CSharp):
    1. IEnumerator Merge ()
    2. {
    3.     float timeStamp = Time.time;
    4.     float lerpTime = 0.5f / maxDistance;
    5.     while (currentDistance > 0)
    6.     {
    7.         timeStamp = Time.time;
    8.         while (Time.time < timeStamp + lerpTime)
    9.         {
    10.             float t = (Time.time - timeStamp) / lerpTime;
    11.             //here I iterate through all the units with a matching distance.
    12.             //Lerp from their current to next position
    13.         }
    14.         currentDistance--;
    15.     }
    16. }
    The problem is that this is really linear and I'd like to ease it. Something along the lines of
    Code (CSharp):
    1. float t = (Time.time - timeStamp) / lerpTime;
    2. t = Mathf.Sin (0.5f * Mathf.PI * t);
    I can't just toss this into my while loop since it'll ease every segments individually. I'd like to ease the whole thing. E.g, 1 to 2 would be much faster than 4 to 5. I can't figure this out by myself. Any ideas?
     
  2. Basen1

    Basen1

    Joined:
    Dec 19, 2016
    Posts:
    76
    Do they need to ease in Tile by Tile or just smooth movement first horizontally then vertically?
     
  3. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    992
    Ease from start to finish, once, if that makes any sense.

    A path is defined for each tiles before the coroutine is called so that the tiles know where to navigate. In the image in my previous post, the path for "1" would be 2, 3, 4 and then it ends at 5.

    Basically, I'd need to be able to navigate through all these waypoints, following one single smoothing curve.
     
  4. Basen1

    Basen1

    Joined:
    Dec 19, 2016
    Posts:
    76
    Can you do Time.deltaTime instead of Time.time? See what that does for you please.
     
    Last edited: Jul 26, 2017
  5. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    992
    Perhaps I'm not clear enough. Right now, my interpolation routine covers the movement on a segment basis. E.G. Below, the routine is called once for the movement covering from (0, 3) to (0, 2), and then another time for (0, 2) to (1, 2), and so on until it reaches (1, 0). It's easy for me to smooth the movement between each segments.

    What I'm trying to accomplish is to smooth the movement over all the segments as a whole, not individually.
    halp 2.0.png
     
  6. Basen1

    Basen1

    Joined:
    Dec 19, 2016
    Posts:
    76
    May I see your move function?
     
  7. Basen1

    Basen1

    Joined:
    Dec 19, 2016
    Posts:
    76
    I just think your whole Merge function is too complicated. I am not sure how you are calling the move function but if it is in the Update function then it should be as simple as to just feed the Time.time value into Mathf.Sin as the Vector3.Lerp step.
     
  8. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    992
    Sure thing. Here it is.
    Code (CSharp):
    1.  
    2. IEnumerator Merge ()
    3. {
    4.     //maxDistance is an int that represents the furthest distance away from the final target
    5.     float mergeTime = 0.5f / maxDistance;
    6.     //Args that will be fed to iTween
    7.     Hashtable args = new Hashtable();
    8.     args.Add("time", mergeTime);
    9.     args.Add("position", Vector3.zero);
    10.  
    11.     while (maxDistance > 0)
    12.     {
    13.         //Creates a list with the units who's distance is matching the distance iterator
    14.         List<Unit> movingUnits = distanceDictionary.Where(pair => pair.Value == maxDistance)
    15.             .Select(pair => pair.Key)
    16.             .ToList();
    17.        
    18.         //Iterates through the moving units and orders them to their new position
    19.         for (int i = 0; i < movingUnits.Count; i++)
    20.         {
    21.             //Following 2 lines of code are basically fetching the world position this unit needs to reach
    22.             Unit target = paths [movingUnits [i]] [maxDistance - 1];
    23.             Vector3 temp = (Vector3) UnitsManager.Instance.GetRealPosition (target.gridPosition);
    24.             args ["position"] = temp;
    25.             iTween.MoveTo (movingUnits [i].gameObject, args);
    26.         }
    27.  
    28.         //Waits for the duration of the movement
    29.         yield return new WaitForSeconds (mergeTime);
    30.  
    31.         //Destroys the units that just moved. In my case it makes sense since they're overlapping with
    32.         //the unit that was the next in the path and that's not visible to the user
    33.         for (int i = movingUnits.Count - 1; i >= 0; i--)
    34.         {
    35.             movingUnits [i].DestroyUnit ();
    36.         }
    37.         maxDistance--;
    38.     }
    39. }
    40.  
     
  9. Basen1

    Basen1

    Joined:
    Dec 19, 2016
    Posts:
    76
    Can you try replacing this line:

    iTween.MoveTo(movingUnits.gameObject, args);

    with this one:
    moveTime = Time.time;
    Vector3.Lerp(movingUnits.gameObject,args["position"],Mathf.Sin(Time.time - moveTime)*args["time"]);

    Hopefully my reasoning is ok, basically what this should do is even though you are iterating through all the move functions you can use the Math.Sin() and as time passes the value of Mathf.Sin should go up before going back down aka easing out. moveTime should be set prior to each objects movement and not before each objects movement iteration.

    That's what I am thinking at least...
     
  10. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    992
    I'm not quite following you mate.

    I could lerp from the start position to the final position over the total period of time, and then apply smoothing, that would smooth the movement overall as intended, but then my units wouldn't follow their paths and they'd go directly to the end point.

    Unless I'm misunderstanding you?
     
  11. Basen1

    Basen1

    Joined:
    Dec 19, 2016
    Posts:
    76
    No you lerp between your positions like you did before but since the TIME flows normally in the coroutine it is only going to get higher, therefore the speed/step will grow with time no matter which iteration you are in.
     
  12. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    992
    Genuinely trying to figure this out.

    Lerp takes a value between 0 and 1. If I'm interpolating between the very beginning of the routine and the end, how do I move my units accordingly?

    Let's say I've this routine who's only function is to set "t" to its interpolated value. This is called once at the start of the moving routine
    Code (CSharp):
    1. IEnumerator Lerp ()
    2. {
    3.     float timeStamp = Time.time;
    4.     float lerpTime = 0.5f;
    5.     while (Time.time < timeStamp + lerpTime)
    6.     {
    7.         t = (Time.time - timeStamp) / lerpTime;
    8.         t= Mathf.Sin (Mathf.PI * 0.5f * t);
    9.         yield return null;
    10.     }
    11.     t = 1f;
    12. }
    How would I move my units based on that? If it was linear, I could do something like
    Code (CSharp):
    1. float tClone = t - (1 - (distanceRemaining/totalDistance)) * totalDistance);
    and I would know to call my units movement iterations every "totalDuration/waypointsCount" since it's constant.

    How does it work with a smoothed curve? Like, how do I know when I should call my next movement iteration? Obviously the duration between the first and the second call should be different than the duration between the second-to-last and the last call, given the nature of the smoothing.

    Edit : Added game gif. Figured this would provide a bit more information. Currently the movement (when the tiles turn white) is linear, and I'm trying to smooth it as a whole.
    ex.gif
     
    Last edited: Jul 26, 2017
  13. Basen1

    Basen1

    Joined:
    Dec 19, 2016
    Posts:
    76
    Sorry, it should have been Vector3.MoveTowards. The Mathf.Sin function is going to affect the "step" value meaning that it will start slow, ramp up to top of the sine curve then slow back down.