0
votes

Unity | Coroutine accélère après chaque exécution

Ma coroutine pour faire disparaître le joueur après sa mort,

// Fade out ragdoll
IEnumerator RagdollFade()
{
    yield return new WaitForSeconds(3f);

    while (startingColour.a > 0.0f)
    {
        headSR.color = new Color(headSR.color.r, headSR.color.g, headSR.color.b, headSR.color.a - (Time.deltaTime / 1.5f));
        bodySR.color = new Color(bodySR.color.r, bodySR.color.g, bodySR.color.b, bodySR.color.a - (Time.deltaTime / 1.5f));
        leftArmSR.color = new Color(leftArmSR.color.r, leftArmSR.color.g, leftArmSR.color.b, leftArmSR.color.a - (Time.deltaTime / 1.5f));
        rightArmSR.color = new Color(rightArmSR.color.r, rightArmSR.color.g, rightArmSR.color.b, rightArmSR.color.a - (Time.deltaTime / 1.5f));
        leftLegSR.color = new Color(leftLegSR.color.r, leftLegSR.color.g, leftLegSR.color.b, leftLegSR.color.a - (Time.deltaTime / 1.5f));
        rightLegSR.color = new Color(rightLegSR.color.r, rightLegSR.color.g, rightLegSR.color.b, rightLegSR.color.a - (Time.deltaTime / 1.5f));

        yield return null;
    }
}

accélère après chaque exécution.

Par exemple, cette première fois que la coroutine est appelée, tout fonctionne bien et au bout de 3 secondes, le lecteur est éteint. Cependant, la prochaine fois qu'il est appelé 3 secondes ne passent pas avant le fondu, la prochaine fois encore moins de temps, etc.

startingColour est défini dans la fonction Start () .


5 commentaires

Vous ne modifiez jamais startingColour.a pour ne jamais quitter la boucle while ?


@LudovicFeltz mal formulé, je le change - la valeur de départ est définie dans la fonction de démarrage


Êtes-vous sûr de quitter la boucle while?


qu'est-ce que c'est censé faire? startingColour.a a-t-il été modifié ailleurs? Sinon, ne pourriez-vous pas simplement utiliser while (true) ? Et où sont réinitialisés headSR.color etc? Je veux dire une fois que vous les avez évanouis ... est-ce que le séjour s'est évanoui? Dans ce cas, il ne devrait pas être étrange que ce soit plus rapide la deuxième fois. Et comme @LudovicFeltz le dit, vous ne quittez probablement jamais la boucle while? Ainsi, lorsque vous appelez à nouveau StartCoroutine , vous aurez deux routines simultanées en cours d'exécution


@derHugo En gros, quand le joueur meurt, je veux que son corps disparaisse. Parce qu'ils sont une poupée de chiffon, je dois faire disparaître chacune des sections (c'est-à-dire la tête, le corps, etc.). while true est une façon plus simple d'écrire ceci, mon mauvais. J'ai essayé de réinitialiser headSR.color à la fois à la fin de cette coroutine et avant son appel, mais rien ne change. headSR.color = startingColour;


3 Réponses :


4
votes

Il semble que votre valeur startingColour.a soit toujours plus grande que 0 donc la boucle while ne se termine jamais et votre coroutine fonctionne pour toujours. Difficile à dire sans voir le reste de votre code.

Donc, si vous le démarrez une deuxième fois, vous avez maintenant les deux routines en parallèle => maintenant chaque image vous diminuez les alphas du double .. puis triplez .. etc. et il n'attend pas non plus les 3 secondes avant que les premières routines appelées exécutent déjà la boucle while afin qu'elles continuent à diminuer les alphas.


Vous pouvez utiliser StopAllCoroutines ou StopCoroutine afin d'interrompre toutes les routines en cours lors du démarrage d'une nouvelle. Mais c'est en fait plus une sorte de solution de contournement sale.


Je préfère aborder le problème réel et m'assurer que votre boucle while revient, ce qui est actuellement peu probable car vous semblez ne pas changer startColor .a n'importe où.

Ou ajouter un drapeau ne permettant pas du tout les routines parallèles comme par exemple

private bool isFading;

// you can also use a fixed duration and not pass it as parameter
// but this way you are even more flexible
IEnumerator RagdollFade(float duration)
{
    if(isFading) yield brake;

    // prevents other routines
    isFading = true;

    yield return new WaitForSeconds(3f);

    // it is more performant to gather all required information beforehand

    headStartColor = headSR.color;
    bodyStartColor = bodySR.color;
    leftArmStartColor = leftArmSR.color;
    rightArmStartColor = rightArmSR.color;
    leftLegStartColor = leftLegSR.color;
    rightLegStartColor = rightLegSR.color;

    headTargetColor = new Color(headStartColor.r, headStartColor.g, headStartColor.b, 0f);
    bodyTargetColor = new Color(bodyStartColor.r, bodyStartColor.g, bodyStartColor.b, 0f);
    leftArmTargetColor = new Color(leftArmStartColor.r, leftArmStartColor.g, leftArmStartColor.b, 0f);
    rightArmTargetColor = new Color(rightArmStartColor.r, rightArmStartColor.g, rightArmStartColor.b, 0f);
    leftLegTargetColor = new Color(leftLegStartColor.r, leftLegStartColor.g, leftLegStartColor.b, 0f);
    rightLegTargetColor = new Color(rightLegStartColor.r, rightLegStartColor.g, rightLegStartColor.b, 0f);

    var passedTime = 0f;
    while (passedTime < duration)
    {
        // get the interpolation factor from 0 to 1
        var factor = passedTime / duration;
        // for adding additional ease-in and ease-out
        // factor = Mathf.SmoothStep(0, 1, factor);

        headSR.color = Color.Lerp(headStartColor, headTargetColor, factor);
        bodySR.color = Color.Lerp(bodyStartColor, bodyTargetColor, factor);
        leftArmSR.color = Color.Lerp(leftArmStartColor, leftArmTargetColor, factor);
        rightArmSR.color = Color.Lerp(rightArmStartColor, rightArmTargetColor, factor);
        leftLegSR.color = Color.Lerp(leftLegStartColor, leftLegTargetColor, factor);
        rightLegSR.color = Color.Lerp(rightLegStartColor, rightLegTargetColor, factor);


        // avoid overshooting
        passedTime += Mathf.Min(Time.deltatime, duration - passedTime);
        yield return null;
    }

    // reset the flag once routine is finished
    isFading = false;
}

Alors je préfère aussi suggérez d'avoir une seule valeur float que vous utilisez pour la décoloration en utilisant Color.Lerp comme

private bool isFading;

IEnumerator RagdollFade()
{
    if(isFading) yield brake;

    // prevents other routines
    isFading = true;

    ...

    // reset the flag once routine is finished
    isFading = false;
}

Ceci est plus flexible et vous pouvez ajouter une facilité d'entrée et de sortie en utilisant les mathématiques simples que vous aimez .


6 commentaires

Wow merci mec! J'apprécie vraiment que vous preniez le temps d'écrire ceci, je vais jeter un coup d'œil et inclure ce genre de choses à l'avenir. Merci pour ton aide :).


cela vous dérangerait-il alors d'accepter ma réponse? Comme dit, celui que vous avez accepté est plus une solution de contournement sale .. et a été ajouté après mon message btw;)


Haha, vous avez 17,6k points homme - je suis sûr qu'un tick ne fait pas mal. Prenez plutôt mon vote positif actuellement invisible: D. Merci encore et bonne journée :).


@derHugo Totalement d'accord avec Wzrd. Votre réponse est incroyable, mais donnons aussi une chance au nouveau venu :)


@GauravMall Je suis d'accord avec vous deux pour soutenir les nouveaux arrivants .. mais dans les bonnes conditions;) La qualité de l'autre poste est ... eh bien ..


@derHugo D'accord avec vous également. La qualité est de premier ordre. Eh bien, l'OP a ses raisons. Nous pouvons espérer que vous obtiendrez beaucoup de votes positifs. Parfois, certaines réponses sont des tentatives infructueuses. J'ai aussi deux réponses de haute qualité qui n'ont même pas de votes positifs. Ce n'est pas grave, ce qui compte, c'est que vous ayez appris quelque chose.



2
votes

Essayez d'appeler StopCoroutine () avant de démarrer une nouvelle Coroutine. Vous avez peut-être quelques coroutines fonctionnant en même temps.


1 commentaires

Oui, c'était ça, deux coroutines interféraient l'une avec l'autre. Merci beaucoup mec.



1
votes

D'accord, j'ai résolu le problème, et c'est complètement mon problème.

J'ai réalisé que UNE AUTRE coroutine que j'avais interférait avec la coroutine actuelle, c'est pourquoi StopCoroutine () et l'ajout d'un contrôle de fondu ne fonctionnaient pas.

Désolé les gars de ne pas avoir inclus cela dans mon message de question, vous auriez probablement pu m'aider plus efficacement.

Donc, pour tous ceux qui rencontrent des comportements routiniers étranges à l'avenir, assurez-vous que deux coroutines ne s'interfèrent pas.


0 commentaires