✏️
A
👆 직원 한명이 순차적으로 하나씩 일을 처리
👆 직원 두명이 순차적으로 하나씩 일을 처리
그러나 이 경우의 단점은 같은 업무가 동시에 일어났을때 중복되어 충돌이 일어날경우가 있다 이를 방지하기 위하여 유니티에서는 멀티스레드를 사용하지않고 싱글스레드를 사용한다
👆 지원은 한명이지만 동시 다발적으로 여러 일들을 처리하기에 멀티스레드가 하는 역할을 흉내를 낼 수 있다
👇 코루틴 사용법
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
private void Start()
{
StartCoroutine(TestCo());
}
IEnumerator TestCo()
{
yield return new WaitForSeconds(1);
Debug.Log("1초후의 처리");
}
}
✏️ 여기서 IEnumerator 과 yield return 은 무슨 의미를 하는가?
IEnumerator 은 일종의 순서와 같으며 열거자 라고도 한다.
👇Coroutine, StopCoroutine 예시
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
void Start()
{
StartCoroutine(TestCo());
}
IEnumerator TestCo()
{
yield return new WaitForSeconds(1);
Debug.Log("1초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("2초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("3초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("4초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("5초후의 처리");
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
StopCoroutine(TestCo());
}
}
}
이러한 형식의 코루틴과 코루틴을 멈추게 하는 기능을 만들었을 경우 코루틴은 멈추게 될까?
정답은 아니다
왜냐하면 서로 다른함수이기 때문 함수의 이름이 같다고 하여 함수의 내부마저 전부 같다고 할 수 없다
그렇다면 저 코루틴은 멈출수 있는 방법은 없을까? 여러 방법이 있지만 StopCoroutine("TestCo"); 로 리플렉션을 활용할수 있지만 연산이 많이 필요해진다
혹은 testCo = TestCO(); 로 캐싱을 한후 StopCoroutine(testCo); 로 멈추게 하는 방법이 있다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
IEnumerator testCo;
void Start()
{
testCo = TestCo();
}
IEnumerator TestCo()
{
yield return new WaitForSeconds(1);
Debug.Log("1초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("2초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("3초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("4초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("5초후의 처리");
yield return new WaitForSeconds(1);
Debug.Log("6초후의 처리");
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
StopCoroutine(testCo);
}
if (Input.GetKeyDown(KeyCode.V))
{
StopCoroutine(testCo);
}
}
}
👆 코드를 살짝 수정하여 멈추고 다시 실행시키고 멈추고 실행시키는 식으로 만들었을때 IEnumerator 는 순서가 있기에 1, 2, 3, 4, 5.... 의 순서대로 실행된다 위에 말했단 열거자 와 비슷한 맥락이다.
IEnumerator : 특정한 순서
IEnumerable : 순서를 가지고 있는 것
👇 IEnumerator
namespace System.Collections
{
public interface IEnumerator
{
object Current { get; }
bool MoveNext(); // 순서를 준다
void Reset(); // 초기화 시켜준다
}
}
👇 IEnumerable - IEnumerator(순서) 를 가져올수 있는
namespace System.Collections.Generic
{
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
}
👇 List나 Statck 에서 Ienumerator가 사용되는 부분
✏️순서를 가져온다는것은 어떤 의미이기에 List나 특정 콜렉션들은 순서를 따를까??
반복자 패턴을 활용할때에 IEnumerator들을 순차적으로 가져올수 있어야 하기 때문이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 짝수만 들어가는 콜렉션
public class EvenNumberCollections : IEnumerable // IEnumerable 인터페이스 구현해라
{
public List<int> collection = new List<int>();
public void Add(int value)
{
if(value % 2 == 0)
{
collection.Add(value);
}
else
{
Debug.Log(value + "is not even number");
}
}
public IEnumerator GetEnumerator()
{
throw new System.NotImplementedException();
}
}
public class InOrderEnumerator : IEnumerator // IEnumerator 구현해라
{
public object Current => current;
public EvenNumberCollections evenNumberCollections;
public int current;
public int index = 0;
public InOrderEnumerator(EvenNumberCollections inputCollection)
{
evenNumberCollections = inputCollection;
}
public bool MoveNext()
{
current = evenNumberCollections.collection[index];
index++;
if(index < evenNumberCollections.collection.Count)
{
return true;
}
else
{
return false;
}
}
public void Reset()
{
index = 0;
}
}
public class Test : MonoBehaviour
{
public EvenNumberCollections evenNumbers = new EvenNumberCollections();
private void Start()
{
for (int i = 0; i < 100; i++)
{
evenNumbers.Add(i);
}
foreach (int current in evenNumbers)
{
Debug.Log(current);// evenNumbers 는 IEnumerable 이여야 한다
}
}
}
👆 순차적으로 짝수를 출력해내는 IEnumerable 상속
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum Mouse_TYPE
{
RIGHT=1,LEFT=0
}
public class WaitForMouseDown : CustomYieldInstruction
{
private Mouse_TYPE type;
public WaitForMouseDown(Mouse_TYPE type = Mouse_TYPE.LEFT)
{
this.type = type;
}
public override bool keepWaiting => !Input.GetMouseButtonDown((int)type);
}
public class Test : MonoBehaviour
{
private void Start()
{
StartCoroutine(TestCo());
}
IEnumerator TestCo()
{
yield return new WaitForMouseDown(Mouse_TYPE.RIGHT);
Debug.Log("마우스 우클릭 눌림");
yield return new WaitForMouseDown(Mouse_TYPE.LEFT);
Debug.Log("마우스 좌클릭 눌림");
// yield : WaitForMouseDown 가 true가 될때까지 실행해라
// 특정한 상태가 true 가 될때까지 대기
}
}