Math easing problem

3160394--240437--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.

IEnumerator Merge ()
{
    float timeStamp = Time.time;
    float lerpTime = 0.5f / maxDistance;
    while (currentDistance > 0)
    {
        timeStamp = Time.time;
        while (Time.time < timeStamp + lerpTime)
        {
            float t = (Time.time - timeStamp) / lerpTime;
            //here I iterate through all the units with a matching distance.
            //Lerp from their current to next position
        }
        currentDistance--;
    }
}

The problem is that this is really linear and I’d like to ease it. Something along the lines of

float t = (Time.time - timeStamp) / lerpTime;
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?

Do they need to ease in Tile by Tile or just smooth movement first horizontally then vertically?

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.

Can you do Time.deltaTime instead of Time.time? See what that does for you please.

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.

May I see your move function?

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.

Sure thing. Here it is.

IEnumerator Merge ()
{
    //maxDistance is an int that represents the furthest distance away from the final target
    float mergeTime = 0.5f / maxDistance;
    //Args that will be fed to iTween
    Hashtable args = new Hashtable();
    args.Add("time", mergeTime);
    args.Add("position", Vector3.zero);

    while (maxDistance > 0)
    {
        //Creates a list with the units who's distance is matching the distance iterator
        List<Unit> movingUnits = distanceDictionary.Where(pair => pair.Value == maxDistance)
            .Select(pair => pair.Key)
            .ToList();
       
        //Iterates through the moving units and orders them to their new position
        for (int i = 0; i < movingUnits.Count; i++)
        {
            //Following 2 lines of code are basically fetching the world position this unit needs to reach
            Unit target = paths [movingUnits [i]] [maxDistance - 1];
            Vector3 temp = (Vector3) UnitsManager.Instance.GetRealPosition (target.gridPosition);
            args ["position"] = temp;
            iTween.MoveTo (movingUnits [i].gameObject, args);
        }

        //Waits for the duration of the movement
        yield return new WaitForSeconds (mergeTime);

        //Destroys the units that just moved. In my case it makes sense since they're overlapping with
        //the unit that was the next in the path and that's not visible to the user
        for (int i = movingUnits.Count - 1; i >= 0; i--)
        {
            movingUnits [i].DestroyUnit ();
        }
        maxDistance--;
    }
}

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…

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?

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.

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

IEnumerator Lerp ()
{
    float timeStamp = Time.time;
    float lerpTime = 0.5f;
    while (Time.time < timeStamp + lerpTime)
    {
        t = (Time.time - timeStamp) / lerpTime;
        t= Mathf.Sin (Mathf.PI * 0.5f * t);
        yield return null;
    }
    t = 1f;
}

How would I move my units based on that? If it was linear, I could do something like

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.
3160786--240459--ex.gif

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.