0
\$\begingroup\$

How The Game Works

You grab and drag an object around. Once you let go, it interpolates to a certain, variable position, and that's what I'm trying to do here.

Problem Description

I'm talking about vectors, but simplifying that to ordinary numbers for the sake of an example, if A is 0 and B is 1, the object would go something like this:

  1. 0.0
  2. 0.2
  3. 0.5
  4. 0.9
  5. 1.3
  6. 0.9
  7. 1.1
  8. 1.0

What I've Tried

private IEnumerator GoTo(Vector2 endPosition) {
    float elapsed = 0;
    float duration = 1f;

    while (elapsed <= duration) {
        transform.position = Vector2.LerpUnclamped(transform.position, endPosition, animCurve.Evaluate(elapsed / duration));
        distance = CalculateDistance(transform.position, endPosition);
        elapsed += Time.deltaTime;
        yield return new WaitForEndOfFrame();
    }
}

Where animCurve is: animCurve The highest point is approx. 1.3, and the plot converges to 1.0 from there.

Result

This doesn't work at all. Unless something's wrong with Unity's Vector2.LerpUnclamped(), I'm lost.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Your implementation should work but has one issue. Since you are lerping from the current position to the end, the gap between the two shrinks every frame, which means by the time your current position and target position are the same (just before you want to over shoot), the value of t doesn't matter, whether it is 0, 1, 999, or 1.3 it will just return the same value. You need to lerp from a cached start point to the end point so t can evaluate properly on the curve. Otherwise your original solution is pretty solid. \$\endgroup\$ – Benjamin Danger Johnson Aug 22 '20 at 4:11
1
\$\begingroup\$

A few small fixes:

  1. Cache your initial position, and lerp from there to your end, to avoid a feedback loop where transform.position is being used to modify itself.

  2. Advance your elapsed before updating position - that way you finish the loop at your end position, rather than one frame before your end position.

  3. Yield return null to resume next frame with next frame's delta, not at the end of this frame.

All together:

private IEnumerator GoTo(Vector2 endPosition) {
    float elapsed = 0;
    float duration = 1f;

    Vector2 startPosition = (Vector2)transform.position;

    while (elapsed <= duration) {
        elapsed += Time.deltaTime;
        float t = animCurve.Evaluate(elapsed / duration));
        transform.position = Vector2.LerpUnclamped(startPosition, endPosition, t);
        distance = CalculateDistance(transform.position, endPosition);
        yield return null;
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ Thank you! Is there any way to turn the transition from a fixed to variable duration? If possible, I'd like for it to take as long as the distance. I'm primarily using the method in 2 situations, and one requires traveling a much longer distance the other. Having the same duration for both means one is a lot slower than the other. \$\endgroup\$ – verified_tinker Aug 22 '20 at 5:33
  • \$\begingroup\$ My idea is to Evaluate() distance/origDistance instead of elapsed/duration, but I'm not sure what to put inside the while statement. Ideally, I'd ensure the distance is exactly 0, but given a floating point's inaccuracy, I don't think that could work reliably. \$\endgroup\$ – verified_tinker Aug 22 '20 at 5:40
  • \$\begingroup\$ Using distance inside the loop isn't safe, because you overshoot. So it doesn't vary monotonically with progress. However, outside the loop you can scale duration by distance to get a longer run when the initial distance is larger. \$\endgroup\$ – DMGregory Aug 22 '20 at 11:43
  • \$\begingroup\$ I see an edit proposal offering a new solution based on distance. I recommend sharing that as its own answer that we can upvote separately. \$\endgroup\$ – DMGregory Aug 28 '20 at 13:03
  • \$\begingroup\$ Not a new solution; an extension of yours. I took your comment and turned it into code for my project, then figured I should share it. But it doesn't answer my problem on its own, it just extends yours. \$\endgroup\$ – verified_tinker Aug 28 '20 at 13:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.