본문 바로가기
R&D

Unity, 전역으로 코루틴 사용하기(Static Coroutine)

by Client. DJ 2022. 7. 24.
반응형

이미지 설명

정적 코루틴 클래스

유니티를 사용하다보면 코루틴(Coroutine)을 많이 사용하게 되는데, 컴포넌트를 사용 중인 게임 오브젝트가 비활성화 되면 중단되어버립니다. 코루틴을 많이 사용하게 되면 왜 이렇게 사용하게 되는지 이해가 되는데, 주로 컴포넌트를 사용 중인 게임 오브젝트에서 개별적으로 처리하기 위함입니다. 하지만 사용을 하다보면 쓰레드의 백그라운드 워커처럼 코루틴을 백그라운드에서 사용하고 싶은 경우가 생깁니다. 예를 들어서 쓰레드에서는 처리하기 애매한 Resources.LoadAsync()를 연계해서 쓰고 싶은데 쓰레드를 생성해서 사용하기에는 무리가 있습니다.

스크립트

1. StaticCoroutine.cs

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

public class StaticCoroutine : MonoBehaviour
{
    private static StaticCoroutine instance = null;

#if UNITY_EDITOR
    [Serializable]
    private class CoroutineRecord
    {
        public string name;
    }

    [SerializeField] private List<CoroutineRecord> coroutineRecords = new List<CoroutineRecord>();
#endif

    /// <summary>
    /// Initialize StaticCoroutine after the scene has loaded.
    /// </summary>
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    private static void OnLoad()
    {
        if (instance == null)
        {
            GameObject go = new GameObject("StaticCoroutine");
            instance = go.AddComponent<StaticCoroutine>();
            DontDestroyOnLoad(go);
        }
    }

    /// <summary>
    /// Start static coroutine.
    /// </summary>
    /// <param name="enumerator"></param>
    /// <returns></returns>
    public static Coroutine StartStaticCoroutine(IEnumerator enumerator)
    {
        return instance.StartProcess(enumerator);
    }

    /// <summary>
    /// Start enumerator.
    /// </summary>
    /// <param name="enumerator"></param>
    /// <returns></returns>
    private Coroutine StartProcess(IEnumerator enumerator)
    {
        return StartCoroutine(StartEnumerator(enumerator));
    }

    /// <summary>
    /// Mamaged enumerator method.
    /// </summary>
    /// <param name="enumerator"></param>
    /// <returns></returns>
    private IEnumerator StartEnumerator(IEnumerator enumerator)
    {
#if UNITY_EDITOR
        CoroutineRecord coroutineRecord = null;
        var st = new System.Diagnostics.StackTrace(true);
        if (st != null)
        {
            var sf = st.GetFrame(6);
            if (sf != null)
            {
                var filePath = sf.GetFileName().Split('\\');
                var fileName = filePath[filePath.Length - 1];
                var methodName = sf.GetMethod().ToString();
                coroutineRecord = new CoroutineRecord { name = $"[{DateTime.Now.ToString("hh:mm:ss")}] {fileName} >> {methodName}"};
                coroutineRecords.Add(coroutineRecord);
            }
        }
#endif
        yield return enumerator;
#if UNITY_EDITOR
        if (coroutineRecord != null)
        {
            coroutineRecords.Remove(coroutineRecord);
        }
#endif
    }
}

2. StaticCoroutineInspector.cs 

- Editor 폴더에서 생성해야합니다.

- 디버깅을 위해 참고하기 위한 스크립트로, 필수가 아닌 스크립트입니다.

using UnityEditor;
using UnityEditorInternal;

[CustomEditor(typeof(StaticCoroutine))]
public class StaticCoroutineInspector : Editor
{
    private ReorderableList reorderableList;

    private void OnEnable()
    {
        reorderableList = new ReorderableList(serializedObject, serializedObject.FindProperty("coroutineRecords"), false, false, false, false);
    }

    public override void OnInspectorGUI()
    {
        //base.OnInspectorGUI()
        serializedObject.Update();
        reorderableList.DoLayoutList();
        serializedObject.ApplyModifiedProperties();
    }
}

예제

private IEnumrator Start()
{
	yield return StaticCoroutine.StartStaticCoroutine(LoadDatas());
}

마무리

이러한 방법을 사용하면, 전역으로 코루틴을 이용할 수 있으며, 게임오브젝트가 꺼져서 중간에 멈출 우려도 없어집니다. 기본적으로 코루틴 구조로 이루어지다보니 유니티에서 "yield return ~"으로 연계되는 함수를 이용할 수 있습니다.


참고: https://docs.unity3d.com/kr/2021.3/Manual/Coroutines.html

 

반응형

댓글