Your problem is very similar to this previous question "Why is Vector3.MoveTowards only working on a single frame?"
Like this other user, you're testing for a fleeting event: GetMouseButtonDown(0)
is true only for one frame when the mouse button is pressed. If the mouse button is held down or released, it will be false on subsequent frames, so the outermost if
block will be skipped entirely.
Inside this fleeting event response, you're calling on a math function as though you were kicking off a fire-and-forget tweening library - assuming that once you've called Lerp
once, it will somehow remember to keep calling itself every frame afterward until the transition you're trying to complete is done.
But Lerp
is not a coroutine that says "continue modifying this variable a little each frame until the destination value is reached" - it's just a math expression, like +
or *
, that says "blend these two numbers by this amount." It has no knowledge of transitions or frames. Every time you want to get new numbers out of it, you need to call it again.
But, we can easily use it to make the fire-and-forget tweening function you seem to want, like so:
// Store a reference to our coroutine so we can interrupt it if needed.
Coroutine _zooming;
// "IEnumerator" marks this as a routine that can pause & automatically
// resume at a later time (say, advancing a little each frame)
IEnumerator ZoomTo(float newFov, float duration) {
// Remember where we started from, so we can smoothly control the curve.
float originalFov = mainCam.fieldOfView;
float speed = 1f/duration;
float t = 1.0f;
// Loop multiple times until we've used up our full duration.
do {
// Blend one more step toward our destination value.
t = Mathf.Clamp01(t - speed * Time.deltaTime);
mainCam.fieldOfView = Mathf.Lerp(newFov, originalFov, t*t);
// Return control to the main game thread for one frame,
// then resume next frame.
yield return null;
} while(t > 0f);
// We've finished our work, so clear the stored coroutine to signal this.
_zooming = null;
}
You'll note I'm doing something a little funny here and lerping from a weight of 1 down to 0, instead of 0 to 1. That's because I noticed you were using a formula that gives an ease-out blend, where the change starts fast and slows down toward the end (although your formula was implemented incorrectly - see here for how to fix that). So here I've mimicked that by using t*t
as the blending weight, which levels off as it approaches zero.
Now when you want to kick off your zoom, you can write:
if(_zooming == null)
_zooming = StartCoroutine(ZoomTo(newFov, zoomDuration));
The if
above ensures the previous zoom has to finish before you can start a new one. Or, if you want to interrupt a zoom-in-progress instead, you can write
if(_zooming != null)
StopCoroutine(_zooming);
_zooming = StartCoroutine(ZoomTo(newFov, zoomDuration));
if
statements. Which one are you referring to? \$\endgroup\$