Simplify this code

Here’s a coroutine, it has two very similar loops that lerps the cam.LerpX or cam.LerpY depending on the CameraBoundary.Mode, the code works fine but whenever I see repeating lines of code it usually means that there is room for improvement, can this be simplified to a single loop? I don’t understand how to have a variable that references either cam.LerpX or cam.LerpY.

   IEnumerator TransitionCoroutine(CameraBoundary.Mode mode, bool transitionIn)
    {
        float time = transitionIn ? transitionTime : -transitionTime;
        float lerpValue = transitionIn ? 1 : 0;

		if (mode == CameraBoundary.Mode.Vertical)
        {
            while (cam.lerpX != lerpValue)
            {
				if(cam.lerpX == 1)
					yield return new WaitForSeconds(0.1f);
				if (controller.transitioning)
                     yield break;

                cam.lerpX = Mathf.Clamp01(cam.lerpX + time * Time.deltaTime);
                yield return null;
			}
        }
        else if (mode == CameraBoundary.Mode.Horizontal)
        {
            while (cam.lerpY != lerpValue)
            {
                if(cam.lerpY == 1)
					yield return new WaitForSeconds(0.1f);
                if (controller.transitioning)
                    yield break;
                    
                cam.lerpY = Mathf.Clamp01(cam.lerpY + time * Time.deltaTime);
                yield return null;
            }
        }
    }

It is a very good instinct to react to repeating lines with “that could be improved” - it usually is true. In this case a simple factoring out of the block of the branch and eliminating differences with a common variable should do it:

private IEnumerator TransitionCoroutine (CameraBoundary.Mode mode, bool transitionIn) {
    float time = transitionIn ? transitionTime : -transitionTime;
    float lerpValue = transitionIn ? 1 : 0;

    if (mode == CameraBoundary.Mode.Vertical) { yield return LerpRoutine(cam.lerpX, lerpValue); }
    else if (mode == CameraBoundary.Mode.Horizontal) { yield return LerpRoutine(cam.lerpY, lerpValue); }
}

private IEnumerator LerpRoutine (float camLerp, float lerpValue) {
    while (camLerp != lerpValue) {
        if (camLerp == 1)
            yield return new WaitForSeconds(0.1f);
        if (controller.transitioning)
            yield break;

        camLerp = Mathf.Clamp01(cam.lerpY + time * Time.deltaTime);
        yield return null;
    }
}

Some further possible improvements:

  • instead of if-else-if-else... chain use a switch-case for branching on the value of CameraBoundary.Mode (I’m assuming it is an enum)

  • as Piyush_Pandey said, cache the wait object (common type is YieldInstruction), even if just as a local variable before the while loop

Without repeating code you try something like this:

	IEnumerator TransitionCoroutine(CameraBoundary.Mode mode, bool transitionIn)
	{
		float time = transitionIn ? transitionTime : -transitionTime;
		float lerpValue = transitionIn ? 1 : 0;

		float lerpTarget;

		if (mode == CameraBoundary.Mode.Vertical)
		{
			lerpTarget = cam.lerpX;
		}
		else
		{
			lerpTarget = cam.lerpY;
		}

		while (lerpTarget != lerpValue)
		{
			if(lerpTarget == 1)
				yield return new WaitForSeconds(0.1f);
			if (controller.transitioning)
				yield break;

			lerpTarget = Mathf.Clamp01(lerpTarget + time * Time.deltaTime);
			yield return null;
		}
	}

I’ve decided to go with what Strotosome and Sonky108 have suggested:

 IEnumerator TransitionCoroutine(CameraBoundary.Mode mode, bool transitionIn)
{
    float time = transitionIn ? transitionTime : -transitionTime;
    float lerpValue = transitionIn ? 1 : 0;
	float lerpTarget = mode == CameraBoundary.Mode.Vertical ? cam.lerpX : cam.lerpY;
	WaitForSeconds waitForMillisecond = new WaitForSeconds(0.1f);

	while (lerpTarget != lerpValue)
	{
		if (lerpTarget == 1)
			yield return waitForMillisecond;
		if (controller.transitioning)
			yield break;

		lerpTarget = Mathf.Clamp01(lerpTarget + time * Time.deltaTime);

		if (mode == CameraBoundary.Mode.Vertical)
			cam.lerpX = lerpTarget;
		else
			cam.lerpY = lerpTarget;

		yield return null;
	}
}

Thanks for the suggestions!