Home > database >  Two scripts do the "same" thing but one works perfectly and the other doesnt
Two scripts do the "same" thing but one works perfectly and the other doesnt

Time:02-22

I have two scripts that will do mostly the same thing, which is call a coroutine, and slowly regen stamina. Thing is in the second script, it instantly fills the stamina up to max, when the other increases it by 5 every second

This doesn't make any sense cause I basically copied the second script part from the first, and the first works perfectly. I have no idea why

https://pastebin.com/pE1vjisj

Has all my code, but the important stuff is this:

(Not working)
    void StopSprinting()
    {
        isSprinting = false;
        moveSpeed = 5;

        CallStam();
    }

    async void CallStam()
    {
        await Task.Delay(2500);

        player.SetStamBool();
    }
(Works perfectly)
    void Melee()
    {
        Vector2 attackDetectionPosition = attackDetection.position;
        Vector2 attackDirection = attackDetectionPosition   movementDirection;
 
        Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackDirection, attackRange, enemyLayers);

        foreach (Collider2D enemy in hitEnemies)
        {
            Debug.Log("We hit "   enemy.name);
        }
 
        if (player.CurrentStamina > 10)
        {
            player.CurrentStamina -= 10;
 
            //Deal Damage
 
            player.StamRegen = false;
            CallStam();
        }
        else if (player.CurrentStamina > 0)
        {
            //Deal half damage

            player.StamRegen = false;
            CallStam();
        }
    }

    async void CallStam()
    {
        await Task.Delay(2500);

        player.SetStamBool();
    }
    public void SetStamBool()
    {
        StamRegen = true;

        StartCoroutine(RegenerateStamina());
    }

    IEnumerator RegenerateStamina()
    {
        while (StamRegen == true && CurrentStamina < MaxStamina)
        {
            yield return new WaitForSeconds(1);

            CurrentStamina  = 5;
        }

        if (CurrentStamina > MaxStamina)
        {
            int subtractionAmount = CurrentStamina - MaxStamina;

            CurrentStamina -= subtractionAmount;
        }
    }

Sorry if I don't respond for a while

CodePudding user response:

Your problem is most likely that the StopSprinting function is being called over and over again which makes WaitForSeconds redundant. You need to find a way to only trigger the coroutine function once, and here is my suggestion:

public void SetStamBool()
{
    if(!StamRegen){
        StamRegen = true;
        StartCoroutine(RegenerateStamina());
    }
}

Running should obviously set StamRegen to false for this logic to work.

On a side note, you should know that you can use a boolean on its own as a condition. So StamRegen == true is the very same as StamRegen on its own. Also, please keep the same casing convention for all your variables not to mix them with function names or classes, so StamRegen should be camelCase stamRegen to match the variable casing that you are following.

CodePudding user response:

First of all: These are not doing the same! In the one hat is working you set

player.StamRegen = false;

in the other one you forgot that so it is possible that another routine is still running at the same time.

In general you could being end up with multiple parallel runnin routines!


Either way your mixing in of the async calls is not good! I would rather explicitly interrupt any running Coroutine and simply put the initial delay into the routine itself!

In the player have

// holds the currently running routine
private Coroutine _currentStaminaRegenaration;

public void RegenerateStamina(float initialDelay)
{
    // if there is already a routine running stop it
    if(_currentStaminaRegenaration != null)
    {
        StopCoroutine(_currentStaminaRegenaration);
    }

    _currentStaminaRegenaration = StartCoroutine(RegenerateStaminaRoutine(initialDelay));
}

IEnumerator RegenerateStaminaRoutine(float initialDelay)
{
    // before starting the regeneration first run your initial delay
    yield return new WaitForSeconds(initialDelay);

    while (CurrentStamina < MaxStamina)
    {
        yield return new WaitForSeconds(1);

        CurrentStamina  = 5;
    }

    // Instead of your complex check and subtraction simply use 
    CurrentStamina = Mathf.Min(CurrentStamina, MaxStamina);

    // never sure if this is needed but just in case reset
    _currentStaminaRegenaration = null;
}

and now everywhere instead of

player.StamRegen = false;
CallStam();

all you need to do is calling

player.RegenerateStamina(2.5f);

if the 2.5f seconds is the same delay everywhere anyway you ca as well code it directly into the Coroutine itself then you don't even need to pass it in as parameter.

  • Related