이제 IDE에서 SomeCoroutine이 정말로 사용되는 코루틴인지 확인할 수 있게 된 것이다.
바보같이 코루틴만 실행하면 내부가 자동으로 반복문이 된다고 생각한적이 있다.
따로 반복문으로 계속 반환해주면 된다.
void Awake()
{
StartCoroutine(nameof(SomeCoroutine));
}
IEnumerator SomeCoroutine()
{
while(true) 아무 조건 없이 true뿐이니까 무한 반복이 된다.
{
Debug.Log("1초마다 출력");
yield return new WaitForSeconds(1);
}
}
StopCoroutine이 제대로 작동하지 않는 경우
Coroutine 타입 변수 사용
Coroutine runningCoroutine = null; //코루틴 변수. 1개의 루틴만 돌리기 위해 저장한다.
//만약 이미 돌고 있는 코루틴이 있다면, 정지시킨 후 코루틴을 실행한다.
if(runningCoroutine != null)
{
StopCoroutine(runningCoroutine);
}
runningCoroutine = StartCoroutine(ScaleUp()); //코루틴을 시작하며, 동시에 저장한다.
--------------------------------------------------------------------------------
IEnumerator 타입 변수 사용
void Enter()
{
만약 stopcoroutine 할 때 작동이 안된다면,
StopCoroutine(nameof(SomeCoroutine));
IEnumerator CoTemp = null;
CoTemp = SomeCoroutine();
StartCoroutine(CoTemp);
if(CoTemp != null)
StopCoroutine(CoTemp);
}
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
즉, IEnumerator는
지금 몇번쨰 까지 읽었는지(state)를 기억한다.
MoveNext()호출 하면 다음 순번으로 이동.
Current를 요구할 때 해당 순번의 개체를 리턴.
그러면 이런 구조로 볼 수 있겠다. IEnumerable에서 GetEnumerator()호출하면 -> IEnumerator는 Current(), MoveNext(), Reset()등 현재 객체 접근하는 구조. Enuerable 인터페이스에는 foreach 구문에서 필요한 멤버들을 약속한 IEnumerator 개체를 반환하는 GetEnumerator 메서드를 제공하고 있다. // 아직은 뭔소린지 도통 모르겠다..
yield를 통해 IEnumerable, IEnumerator 를 상속받는 객체를 간단하게 구현할 수 있는 것이나 마찬가지다. 마치 일시정지와 같은 기능이다.
yield break; 코루틴을 끝낸다.
yield return new WaitForSecondsRealtime (float time); WaitForSeconds와 하는 역할은 동일하지만 결정적으로 다른것은, Scaled Time의 영향을 받지 않고 현실 시간 기준으로만 동작
yield return new WaitForFixedUpdate (); 다음 FixedUpdate() 가 실행될때까지 기다리게 됩니다. 이 FixedUpdate()는 Update()와 달리 일정한 시간 단위로 호출되는 Update() 함수라고 생각하시면 됩니다.
yield return new WaitForEndOfFrame (); 하나의 프레임워 완전yield return null;히 종료될 때 호출이 됩니다. Update(), LateUpdate() 이벤트가 모두 실행되고 화면에 렌더링이 끝난 이후에 호출
yield return null; 다음 Update() 가 실행될때까지 기다린다는 의미를 갖게 됩니다. 좀 더 정확하게는 Update()가 먼저 실행되고 null을 양보 반환했던 코루틴이 이어서 진행 됩니다. 그 다음에 LateUpdate()가 호출
yield return new WaitUntil (System.Func predicate); WaitUntil에 실행하고자 하는 식을 정의해 두면 매번 Update() 와 LateUpdate() 이벤트 사이에 호출해 보고 결과값이 true면 이후로 재진행
yield return new WaitWhile(System.Func predicate); WaitWhile은 WaitUntil과 동일한 목적을 가지고 있지만 한가지만 다릅니다. WaitUntil은 람다식 실행 결과값이 true가 될때까지 기다린다면 WaitWhile은 false가 될때까지 기다립니다. 즉 WaitWhile은 결과가 true인 동안 계속 기다린다.
yield return StartCoroutine (IEnumerator coroutine); 코루틴 내부에서 또다른 코루틴을 호출할 수 있습니다. 물론 그 코루틴이 완료될 때까지 기다리게 됩니다. 의존성 있는 여러작업을 수행하는데에 유리하게 사용.
yield return StartCoroutine (IEnumerator coroutine); 코루틴 내부에서 또다른 코루틴을 호출할 수 있습니다. 물론 그 코루틴이 완료될 때까지 기다리게 됩니다
Linq는 데이터를 찾고 병합하고 정렬하는 부분을 해결해 준다. DB(데이터베이스) 쪽에 자주 사용한다고 한다.
쿼리는 데이터 소스에서 데이터를 검색하는 식이다.
Linq는 다양한 데이터 소스 및 형식에 사용할 수 있는 일관된 모델을 제공함으로써 단순화한다.
쿼리 작업의 세 부분
1. 데이터 소스 가져오기
from num in numbers - 어떤 데이터 집합에서 찾을 것인가?
2. 쿼리 만들기
where - 어떤 값의 데이터를 찾을 것인가?(조건부로 생각하면 됨)
orderby - 데이터 정렬을 어떻게 할 것인가?
select - 어떤 항목을 추출 할 것인가?
3. 쿼리 실행
쿼리는 쿼리 변수에 저장되고 쿼리식으로 초기화된다.
쿼리 변수 자체는 쿼리 명령을 저장할 뿐,
실제 쿼리 실행은 foreach문에서 쿼리 변수가 반복될 때 까지 지연된다.
from에서 데이터 소스를 지정하고
where에서 필터를 적용하며
selct에서 반환되는 요소의 형식을 지정한다.
실수 간의 %(퍼센트 연산자) 연산의 결과 값은, 나눗셈의 몫이 정수일 때의 나머지 값이다.
2.48 % 1.2
= 2.48 - 1.2 = 1.28 - 1.2 = 0.08 <- 결과값
using System.Linq;
class From
{
static void Main(string[] args)
{
int[] numbers = { 9, 2, 6, 4, 5, 3, 7, 8, 1, 10};
var result = from n in numbers //var(IEnumerable<int>)이므로 result는 List다
where n % 2 == 0 // 나머지가 없으면 짝수이며 조건으로 참이다
orderby n
select n;
foreach (int n in result)
Console.WriteLine($"짝수 : {n}");
// 2,4,6,8,10이 나옴
}
}
실제 활용
<문제 해결>
문제가 onCheckEvent로 앤드드래그 이벤트가 발생되면 CheckImage()함수를 실행해서
일정 거리만큼 가까워지면 움직이는 오브젝트는 꺼지고 기존에 있던 오브젝트를 켜서 퍼즐을
맞춘것 처럼 했고, 배열로 SetActive(false)만 체크하거나 해제될 때 마다 숫자를 체크해서
미션성공을 예상했다.
그런데 밑에는 없지만 업데이트나 코루틴으로 false체크하면 하나만 체크되도 계속 체크가 되며
앤드드래그 이벤트가 발생할 때만 체크해도 이전에 체크되는 숫자가 첫 번째를 맞추면 1이 올라가지만
두 번째를 맞추면 그전 이벤트도 체크되어 (기존1 + (배열로 이전 이벤트1 + 현재 이벤트1))=3이
되어 멘붕에 빠져있었다. 사수의 도움으로 새롭게 배웠다.
public override void Init()
{
for (int i = 0; i < dragImage.Length; i++)
{
dragImage[i].onCheckEvent = () => { CheckImage(); };
}
}
public void CheckImage()
{
for (int i = 0; i < tr_Begin.Length; i++)
{
radius = tr_Begin[i].GetComponent<BoxCollider2D>().edgeRadius / 2;
distance = Vector3.Distance(tr_Begin[i].transform.position, tr_Attach[i].transform.position);
if (distance <= radius)
{
tr_Attach[i].SetActive(false);
tr_Begin[i].SetActive(true);
}
}
IEnumerable<GameObject> dassdads = from dasasd in tr_Attach
where dasasd.activeInHierarchy == false // 하이어라키창 false일 때(조건)
select dasasd; // 호출
Debug.Log("dassdads.ToList().Count : " + dassdads.ToList().Count);
if (dassdads.ToList().Count == tr_Attach.Length)
{
Debug.Log("성공");
Check_Mission(true);
}
}
class IntroToLINQ
{
static void Main()
{
// 1. 사용할 데이터 집합(Data source).
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
// 2. 쿼리 만들기
// numQuery is an IEnumerable<int>
var numQuery = //(IEnumerable<int> numQuery) 와 같다.
from num in numbers // 데이터 집합
where (num % 2) == 0 // 필터
select num; // 반환
// 3. Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
}
}