The code below might look complicated but once you understand it, you will be able to see its power of reusablity
. (it's kind of countup
but further down you will understand how to make it countdown
if you understand how the code works)
public IEnumerator Count(
float targetTime,
System.Action<float> receiveTimeElapsed = null,
System.Func<bool> actionCondition = null,
System.Action conditionalAction = null,
System.Action onCountStart = null,
System.Action onCountEnd = null)
{
onCountStart?.Invoke();
float timeElapsed = 0f;
receiveTimeElapsed?.Invoke(timeElapsed);
while (timeElapsed < targetTime)
{
if (actionCondition != null && actionCondition.Invoke())
conditionalAction?.Invoke();
yield return null;
timeElapsed += Time.deltaTime;
receiveTimeElapsed?.Invoke(timeElapsed);
}
if (actionCondition != null && actionCondition.Invoke())
conditionalAction?.Invoke();
onCountEnd?.Invoke();
}
private float _timeElapsed;
private int _count;
private void Awake()
{
this.StartCoroutine(
this.Count(
5f,
(timeElapsed) =>
{
this._timeElapsed = timeElapsed;
Debug.Log("Time Elapsed: " + this._timeElapsed);
},
() => { return this._timeElapsed >= (this._count + 1); },
() =>
{
this._count++;
Debug.Log("Countdown: " + this._count);
},
() => { Debug.Log("Countdown: " + this._count); },
() => { Debug.Log("On countdown end"); }
)
);
}
If you think that it's too much or you may not need all this checking for null. To simplify the method you could create a similar methods that will do the same but without some actions.
But I would optimize only when it hits the performance, though, I like early optimization. This one is not the case as it's not intended to be used 1000000 times per frame. As well as removing null checks and some actions would be a micro-optimization.
Also you can always add more actions, for while loop condition check and for the way time elapsing is calculated.
For example, add getElapsingValue
:
public IEnumerator Count(
float targetTime,
System.Func<float> getElapsingValue,
System.Action<float> receiveTimeElapsed = null,
System.Func<bool> actionCondition = null,
System.Action conditionalAction = null,
System.Action onCountStart = null,
System.Action onCountEnd = null)
{
onCountStart?.Invoke();
float timeElapsed = 0f;
receiveTimeElapsed?.Invoke(timeElapsed);
while (timeElapsed < targetTime) // You want to add func here to make it more scalable.
{
if (actionCondition != null && actionCondition.Invoke())
conditionalAction?.Invoke();
yield return null;
timeElapsed += getElapsingValue.Invoke();
receiveTimeElapsed?.Invoke(timeElapsed);
}
if (actionCondition != null && actionCondition.Invoke())
conditionalAction?.Invoke();
onCountEnd?.Invoke();
}
private float _timeElapsed;
private int _count;
private void Awake()
{
this.StartCoroutine(
this.Count(
5f,
() => { return Time.deltaTime; },
(timeElapsed) =>
{
this._timeElapsed = timeElapsed;
Debug.Log("Time Elapsed: " + this._timeElapsed);
},
() => { return this._timeElapsed >= (this._count + 1); },
() =>
{
this._count++;
Debug.Log("Countdown: " + this._count);
},
() => { Debug.Log("Countdown: " + this._count); },
() => { Debug.Log("On countdown end"); }
)
);
}
To actually take countdown
value you need to edit the method. Or you could simply do this this._countdown - this._count
which will give you the desired value anyway.