UnityRef is currently in early development. Some features may be incomplete and/or not functioning.

UNITYREF

Your Pit Stop For Solving ANYTHING in Unity

architecture

[Coroutine] Smooth Trajectories: Stop Mid-Path Resets

Solution

coroutinesanimation systemurpeditor scriptingtrajectories

Unity 2021.x - Unity 6.3.x

Published Tue, Mar 10

Issue

 An object intended to follow a parabolic 2D trajectory frequently fails to reach its designated target or exhibits incomplete movement. This behavior is observed when your movement coroutine is repeatedly initiated inside Update(), causing the path calculation to reset prematurely every frame.

Resolve erratic object movement by initiating coroutines once within Start() instead of Update(), and ensure the AnimationCurve is correctly configured.

Explanation

The primary cause of the described issue is the erroneous invocation of your coroutine within the Update() method. The Update() method executes once per frame, leading to the coroutine being started anew in every frame. This continuous re-initialization resets internal state variables, such as timePassed, preventing the coroutine from progressing through its full duration. Consequently, the object appears to move only partially or erratically as it restarts the trajectory calculation constantly.

To rectify this behavior:

  1. Relocate the StartCoroutine call from the Update() method to a lifecycle method that executes only once, such as Start() or Awake().
  2. If the movement must be triggered by a specific event or input, use a boolean flag to ensure the coroutine is not already running before calling StartCoroutine again.
  3. Verify the AnimationCurve asset evaluation to ensure the timePassed value is correctly normalized between 0 and 1.

Additional Tips

  • Ensure your timePassed variable is incremented using Time.deltaTime to maintain frame-rate independent movement.
  • Check that the AnimationCurve wrap mode is set to Clamp to prevent the projectile from looping or snapping back after completion.
  • Utilize Vector2.Lerp for the horizontal axis while using the curve to offset the vertical position for a clean parabolic arc.

Copy


public class projectileController : MonoBehaviour
{
    public AnimationCurve curve;
    [SerializeField] private float duration = 1.0f;
    [SerializeField] private float heightY = 3.0f;
    public GameObject targetObject;

    void Start()
    {
        // Coroutine initiated once upon script enablement to prevent reset
        StartCoroutine(Curve(transform.position, targetObject.transform.position));
    }

    public IEnumerator Curve(Vector3 start, Vector3 target)
    {
        float timePassed = 0f;
        Vector2 end = target;
        while (timePassed < duration)
        {
            timePassed += Time.deltaTime;
            float linearT = timePassed / duration;
            float heightT = curve.Evaluate(linearT);
            float height = Mathf.Lerp(0f, heightY, heightT);
            // Interpolate position and add the vertical offset from the curve
            transform.position = Vector2.Lerp(start, end, linearT) + new Vector2(0f, height);
            yield return null;
        }
    }
}

Related Posts Haven't quite found a solution to your problem? We think these posts might help you.

Content inspired by a Unity discussion post.