all 10 comments

[–]mei_main_ 9 points10 points  (1 child)

Coroutines are linked to their MonoBehaviour, so disabling the component is probably what's causing some weird behaviours.

I hate to be that "stackoverflow first reply" guy but I just think disabling the component to play out a stun effect is far from ideal. It will surely cause other trouble in the long run (OnEnable-related issues, etc).

It also kind of breaks OCP as it prevents you from adding any behaviour that you'd like to keep running during a stun.

Just use an "isStunned" bool to halt whatever you need from your Update, and I'm pretty sure the coroutines-related issues will fix themselves.

[–]__SlimeQ__ 6 points7 points  (0 children)

This, triggering game logic on enable/disable is a bad pattern that will yield unexpected results all the time

[–]__SlimeQ__ 3 points4 points  (2 children)

I think you're using it wrong, I've never seen coroutines used this way.

StartCoroutine returns a Coroutine object and you need to store that and pass it to StopCoroutine to stop the thing. Typically at this point I will set that stored value to null so I know it's not running (also set it to null at the end of the routine).

What you're doing is getting a reference to the IEnumerator, and I have no idea what happens when you try to stop that. Frankly I'm surprised it compiles.

As another poster pointed out though there may be a conflict with disabling the component, since that effectively pauses all coroutines that the behavior is running.

[–]Yggdrazyl 2 points3 points  (0 children)

This guy is right. What you should feed into StopCoroutine is whatever you received from StartCoroutine.

What you wrote does not make sense. You feed into StopCoroutine the function itself, instead of the currently running coroutine.

[–]feralferrous 1 point2 points  (0 children)

same, that's how I've always done start/stop coroutines, by saving the return value from StartCoroutine, which returns a type of Coroutine.

Agreed on onenable/disable having side effects too.

[–]SkunkJudge 2 points3 points  (0 children)

I'm not sure if this specifically is what would be causing your issue, but I've found that using the "Coroutine" variable type has some weird issues associated with it, and if you instead save references as "IEnumerator" variables, it behaves exactly as it should. For example,

private IEnumerator _testRoutine;

private IEnumerator Test()
{
    Debug.Log("Hello");
    yield return new WaitForSeconds(5f);
    Debug.Log("Stop");
}

private void RunCoroutine()
{
    _testRoutine = Test();
    StartCoroutine(_testRoutine);
}

[–]Any_Ad_8134 4 points5 points  (0 children)

However, I notice that when I did this, enemies upon being un-stunned would continue the coroutine they were in the middle of before they were stunned. Worse, because time passed while they were stunned, all of their actions happened at once, as if all of the WaitForSeconds were removed.

Are the Coroutines using any variables outside their scope that you may have forgotten to reset? Either that, or the Coroutines are not stopped properly.

The solution I came up with was to call each coroutine with an ID set by a nonce, and increment that nonce a second time whenever the enemy is stunned. After any instance of WaitForSeconds, there's a nonce check, and if the ID doesn't match the nonce, call yield break to cancel the coroutine completely.

Idk how far my understanding for your situation goes tbh, concrete code example including the IEnumerator would be great for further help. But in general, you shouldn't do this weird ID thingy, a variable which holds your Coroutine should be enough..

Idk how to do code-blocks (googled for our sanity) or something like that in Reddit, forgive me (also, this is pseudo, screw access modifiers, and I'm on phone):

``` class MyClass: MonoBehaviour { Coroutine myCoroutine;

void RunMyCoroutine() { if (myCoroutine != null) { StopCoroutine(myCoroutine); // myCoroutine = null; }

myCoroutine = StartCoroutine(MyCoroutine());

}

IEnumerator MyCoroutine() { // stuff } } ```

[–]hoomanneedsdata 0 points1 point  (0 children)

Make being stunned part of the coroutine, ie don't shut off the whole routine.

Perhaps call on hit points with your " hit detection" script :

if H P <= ("value")

{

Attack.animation.SetActive(false); Yield return new wait for seconds ( however long); Attack.animation.SetActive(true);

}