0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Disable/Enable時のCoroutineを制御する

Last updated at Posted at 2024-06-20

コルーチンは便利ですが、スクリプトをアタッチしているGameObject や 自身のComponentがDisabledになったときの挙動が少し厄介です。

(1)Active all (2)Disable GameObject (3)Disable Component (4)Disable all
image.png image.png image.png image.png
動き続ける 終了する 動き続ける 終了する

(1)通常時は問題ないのですが、(2)いったんgameObject.SetActive(false)したのち、再度gameObject.SetActive(true)すると、動いていたコルーチンは消えてしまいます。
image.png

また、(3)自分自身をthis.enabled = falseしてもコルーチンは動き続けてしまいます。
image.png

そこで、
(2)の場合は再度StartCoroutine(TestCo())
(3)の場合はWaitUntil(() => this.isActiveAndEnabled)で待つようにしてみます。

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace Elix
{
    public class CoroutineCheck : MonoBehaviour
    {
        Coroutine m_co = null;
        // Start is called before the first frame update
        void Start()
        {
            Debug.Log("Start");
        }

        // Update is called once per frame
        void Update()
        {
        }

        IEnumerator TestCo()
        {
            int m_count = 0;
            while (true)
            {
                yield return new WaitUntil(() => this.isActiveAndEnabled);
                Debug.Log($"TestCo: {m_count}");
                m_count++;
                yield return new WaitForSeconds(1f);
            }
        }

        private void OnDisable()
        {
            if(gameObject.activeInHierarchy == false)
            {
                Debug.Log("<OnDisable(GameObject)>");
                if (m_co != null)
                {
                    // All coroutines will stop when the GameObject is disabled.
                    m_co = null;
                }
            }
            else
            {
                // Coroutines are alive when the Comprmemt is disabled.
                Debug.Log("<OnDisable(Component)>");
            }
        }
        private void OnEnable()
        {
            Debug.Log("OnEnable");
            if (m_co == null)
            {
                m_co = StartCoroutine(TestCo());
            }
        }
        private void OnDestroy()
        {
            Debug.Log("[OnDestroy]");
        }
    }
}

一見うまく動作するように見えますが、
(1)->(3)->(4)->(2) のように遷移した場合に動作しなくなります。
結局のところ、OnDisable(),OnEnable()で毎回コルーチンを初期化するのが正解のようです。

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace Elix
{
    public class CoroutineCheck : MonoBehaviour
    {
        [SerializeField] bool m_isResettable = true;
        [SerializeField] TMPro.TextMeshProUGUI m_text = null;
        Coroutine m_co = null;

        // Start is called before the first frame update
        void Start()
        {
            Debug.Log("Start");
            if(!m_isResettable)
            {
                m_co = StartCoroutine(TestCo());
            }
        }

        // Update is called once per frame
        void Update()
        {
        }

        IEnumerator TestCo()
        {
            int count = 0;
            while (true)
            {
                yield return new WaitUntil(() => this.isActiveAndEnabled);
                //Debug.Log($"TestCo: {m_count}");
                m_text.text = $"{count}";
                count++;
                yield return new WaitForSeconds(1f);
            }
        }

        private void OnDisable()
        {
            if (m_isResettable)
            {
                Debug.Log("OnDisable");
                if (m_co != null)
                {
                    StopCoroutine(m_co);
                    m_co = null;
                }
            }
        }
        private void OnEnable()
        {
            if (m_isResettable)
            {
                Debug.Log("OnEnable");
                if (m_co == null)
                {
                    m_co = StartCoroutine(TestCo());
                }
            }
        }
        private void OnDestroy()
        {
            Debug.Log("[OnDestroy]");
        }
    }
}

UniTaskの制御についてはこちら
Awaitableの制御についてはこちら

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?