Restore health over time for a period of time

Hi, how can I make something go for a period of time?

E.g., buff for health restoration, let’s say 15 points of HP over a 5 second duration.

Here’s button code that will start coroutine:

	public void HealingBuff() {
		finishTime = Time.time + duration;

		StartCoroutine(HealingBuffEffect());
	}

And here’s code of coroutine:

	IEnumerator HealingBuffEffect() {
		while (Time.time <= finishTime) {

			currentHealt += 1 * Time.fixedDeltaTime;
			yield return new WaitForSeconds(Time.fixedDeltaTime);
		}
	}

We have finishTime it’s Time.time + duration, in our case Time.time + 5 seconds. So, in coroutine we loop until duration of the buff is over. But we don’t want our health go 15 points every second, instead we want it to scale over time. So, naturally, we will repeat this coroutine over some period of time (in my case I’ve choosen fixedDeltaTime) and also multiply our 15 points by this time. Everything seems good, but I don’t get 75 health restored after 5 second of duration. What’s the problem?

I haven’t tried the following script, but give it a try:

public void HealingBuff()
{
    StartCoroutine(HealingBuffEffect( 15, 5 ));
}

IEnumerator HealingBuffEffect( float healthGain, float duration )
{
    // Do not run the coroutine if the given arguments are not valid
    if ( duration <= Mathf.Epsilon || healthGain <= Mathf.Epsilon )
        yield break;
    float remainingHealth = healthGain;
    float healthPerSecond = healthGain / duration ;
    for ( float t = 0 ; t < duration ; t += Time.deltaTime )
    {
        float delta = healthPerSecond * Time.deltaTime;
        if ( remainingHealth - delta < 0 ) delta = remainingHealth;
        currentHealth += delta;
        remainingHealth -= delta;
        yield return null; // Wait one frame;
    }
}