- Home /
Item duration doesn't stack
Hey so i have PowerUps in my Scene and my Problem is that if i collect a PowerUp and its duration is for example 8 seconds. At Second 7, I collect the same PowerUp again but now the duration is 1s (from the PowerUp before) instead of 9s (the remaining Time of the last PowerUp + the PowerUp again): My Code:
if (other.CompareTag("Powerup"))
{
playerAudio.PlayOneShot(collectSound, sfxVolume);
powerUpIndicator.SetActive(true);
hasPowerup = true;
Destroy(other.gameObject);
StartCoroutine(PowerUpCountdownRoutine());
}
IEnumerator PowerUpCountdownRoutine()
{
yield return new WaitForSeconds(powerupDuration);
powerUpIndicator.gameObject.SetActive(false);
hasPowerup = false;
}
Answer by KoenigX3 · May 31, 2020 at 03:18 PM
Instead of using Coroutines, use a timer variable in Update.
float powerupTimer = 0;
bool hasPowerup = false;
void Update()
{
if(hasPowerup)
{
powerupTimer -= Time.deltaTime;
if(powerupTimer < 0)
{
powerupTimer = 0;
hasPowerup = false;
}
}
}
// When you get a powerup
hasPowerup = true;
powerupTimer += powerupDuration;
Is it not possible to solve it with Coroutines? I have about 20 Items so far (All made with Coroutines) xD
As far as i know, when you called yield return WaitForSeconds in a coroutine, there is no way to stop the command and add another WaitForSeconds to it. You can only do that after the previous one has finished.
I came up with this solution, because i thought it would be the best in a situation like this. But i don't know whether you have different powerups with different timers to implement, and other factors. If you could show me how much the powerups differ from each other, maybe we could find a universal solution.
yeah i think it's the easiest way with a timer in Update
Answer by superjustin5000 · Jun 01, 2020 at 12:36 PM
What about stopping it first in case it's already running by calling stopcoroutine, then startcoroutine
You still need to get the remaining time, and the coroutine won't return it, so you'll have to measure it yourself, with using timers again.
Answer by ADiSiN · Jun 01, 2020 at 01:03 PM
Hi!
With the code that you shared you will need to re-design the Coroutine itself if you want to use Coroutine for that case. It might look like this:
float f_PowerUpDuration = 0;
Coroutine PowerUpCoroutine;
if (other.CompareTag("Powerup"))
{
playerAudio.PlayOneShot(collectSound, sfxVolume);
powerUpIndicator.SetActive(true);
hasPowerup = true;
Destroy(other.gameObject);
// Add to current total f_PowerUpDuration value when receive powerup
f_PowerUpDuration += PowerUpStack;
// If PowerUpCorotuine null what means there is no coroutine running already - we start to execute one
if(PowerUpCoroutine == null)
PowerUpCoroutine = StartCoroutine(PowerUpCountdownRoutine());
}
IEnumerator PowerUpCountdownRoutine()
{
// While total f_PowerUpDuration > 0 we simply decreasing it over time
while (f_PowerUpDuration > 0)
{
f_PowerUpDuration = f_PowerUpDuration - 1 * Time.deltaTime;
yield return null;
}
powerUpIndicator.gameObject.SetActive(false);
hasPowerup = false;
// Reset Corotuine variable as well and overall time as well
PowerUpCoroutine = null;
f_PowerUpDuration = 0;
}
So, we have total power up duration that called f_PowerUpDuration as well as PowerUpCoroutine the Coroutine type of variable to check if our Coroutine is already executing and to not stack them.
When we hit "Powerup" then we add to the overall time f_PowerUpDuration additional time of power up - the PowerUpStack.
Then we check PowerUpCoroutine and only in case if it's null, what means that there is no Coroutine already in execution, then we call and assign new Coroutine.
The Coroutine itself will decrease f_PowerUpDuration variable while it's more than 0 and only after remove your indicator, boolean and stored Coroutine variable. In case where you take powerup and already has Coroutine in execution, by increasing f_PowerUpDuration the Coroutine execution will automatically prolong since it's checking the total f_PowerUpDuration that we increased by taking up new power up.
You can adjust decreasing as you want, for example other way of decreasing might be like this:
while (f_PowerUpDuration > 0)
{
yield return new WaitForSeconds(1f);
f_PowerUpDuration--;
}
So it's up to you.
Hope it helps.
Your answer
Follow this Question
Related Questions
Coroutine won't stop running. Tried String. 1 Answer
Brain exploding ... Problem with an internal Coroutine manager 3 Answers
yield return M() vs yield return StartCoroutine 2 Answers
Is there any performance differences between Coroutine methods ? 3 Answers
Can I use StartCoroutine inside of the same coroutine with a new variable? 0 Answers