원리가 뒤에서 부터 넣어주는건데

 

[0, 1, 2, 3, 4, 5, 6] 이면

 

rnd에서 나온 값이 인덱스가 되고, 그 인덱스에 6의 값이 가며 그 인덱스의 값으로 6으로 간다

중첩이 되어도 어차피 마지막부터 오는거니까 결국은 list 안에서 한번씩은 섞이게 되는 것!

유용할 것 같아서 정리

public static class MyExtensions
{
	//Fisher - Yates shuffle
	public static void Shuffle<T>(this IList<T> list)
	{
		for (int i = list.Count - 1; i > 0; i--)
		{
			int rnd = UnityEngine.Random.Range(0,i);
			T temp = list[i];
			list[i] = list[rnd];
			list[rnd] = temp;
		}
	}

 

'C# > c#' 카테고리의 다른 글

c# 코루틴(Coroutine, IEnumerator, yield), 코루틴 중단이 안될 때  (0) 2022.01.27
c# Linq 쿼리  (0) 2022.01.26

nameof 연산자는 Type이나 메서드 등의 '이름'을 리턴해주는 것이다.
기존에는 이 이름들을 어딘가에 사용해야 할 때에는 string으로 직접 하드코딩을 해야 했으며, 이러한 하드코딩은 IDE에서 제대로 된 참조가 되지 않기 때문에 디버깅에 어려운 점이 있었다.

(유니티의 StartCoroutine은 string을 받기 때문에 이 코루틴이 사용되는 코루틴인지 아닌지 확인하는건 매우 까다롭다.

실제로 b스크립트에서 a스크립트의 코루틴을 실행하고 a에서 stopcoroutine을 했지만 동작하지 않는 오류가 발생했다.)

(IDE : 통합 개발 환경Integrated Development Environment ex) 비주얼스튜디오)

 

하지만 nameof 연산자를 이용하면 마법처럼 이름이라는 문자열을 반환해준다.

void Awake()
{
    StartCoroutine(nameof(SomeCoroutine));
}

IEnumerator SomeCoroutine()
{
    yield return null;
}

이제 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);
}

출처 : https://killu.tistory.com/19

 

[Unity] 코루틴 중단하는 모든 방법 정리 (StopCoroutine)

유니티에서 코루틴을 중단할 때 쓰이는 StopCoroutine은 제대로 작동하지 않는 경우가 많다. 그 이유는 StopCoroutine 메서드를 잘못 사용했기 때문이다. StopCoroutine의 인자는 string, IEnumerator, Coroutine..

killu.tistory.com

<밑에는 좀 더 자세한 설명들>


IEnumerable - 스스로 상태(객체접근 횟수)를 저장하지 못해서

타입의 변수를 인풋으로 받았을 때, 다시 처음부터 콜렉션에 접근해서 객체에 접근한다.

 

IEnumerator - 스스로 상태(객체접근 횟수)를 저장함으로

스스로의 상태 state를 기억하고 있다가 다음 호출시, 그 시첨으로 부터

해당 객체를 뱉어낸다?

출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kimsung4752&logNo=220959490816

 

public interface IEnumerator
{
    object Current { get; }
    bool MoveNext();
    void Reset();
}

즉, IEnumerator는

  • 지금 몇번쨰 까지 읽었는지(state)를 기억한다.
  • MoveNext()호출 하면 다음 순번으로 이동.
  • Current를 요구할 때 해당 순번의 개체를 리턴.

그러면 이런 구조로 볼 수 있겠다. IEnumerable에서 GetEnumerator()호출하면 -> IEnumerator는 Current(), MoveNext(), Reset()등 현재 객체 접근하는 구조. Enuerable 인터페이스에는 foreach 구문에서 필요한 멤버들을 약속한 IEnumerator 개체를 반환하는 GetEnumerator 메서드를 제공하고 있다. // 아직은 뭔소린지 도통 모르겠다..

 

public static System.Collections.IEnumerable SomeNumbers()
{
  yield return 3;
  yield return 5;
  yield return 8;
}
  • IEnumerable, IEnumerator클래스는 컴파일러가 코드를 보고 자동으로 만들어준다.(사용자 정의 컬렉션)
  • IEnumrator가 가지는 state의 초기 값은 -1이다.
  • 자동 생성된 IEnumerator에서 MoveNext() 실행하면 yield return 3; 이전까지 실행하고 state를 0으로 옮긴다.
  • state가 0일 때 Current를 읽으면 3를 리턴한다.
  • 마지막 부분(8)에서 MoveNext()실행 시 false를 리턴한다.
yield return new WaitForSeconds(1);

Current()에서 WaitForSeconds를 리턴 했다면??

  • Update()에서 1초가 지났는지 매프레임 마다 체크.
  • 만약 1초가 지났다면 IEnumerator의 MoveNext()를 호출 한다.
  • 코드 다음 부분이 실행된다.

IEnumerable -> IEnumerator -> 반복기

 

출처 : https://postpiglet.netlify.app/posts/Coroutine-Considerationn/  

출처 : https://www.slideshare.net/jungsoopark104/ienumerator

 

IEnumerator란 무엇인가?

유니티3D를 공부하면서 IEnumerator가 무엇인지 공부한 내용입니다.

www.slideshare.net

 

 

코루틴(Coroutine)

 

기능코루틴  시작코루틴  정지코루틴  재시작기타  
이름을 이용 가능 가능 가능[처음부터 재시작] 매개변수 사용 불가능
함수를 이용 가능 불가능 불가능[정지가 불가능]  
IEnumerator를 이용 가능 가능 가능[멈춘 지점에서 재시작]  
Coroutine을 이용 - 가능 불가능[시작이 불가능]  

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); 코루틴 내부에서 또다른 코루틴을 호출할 수 있습니다. 물론 그 코루틴이 완료될 때까지 기다리게 됩니다

 

'C# > c#' 카테고리의 다른 글

c# List Random sort - 리스트 랜덤 정렬  (0) 2022.03.08
c# Linq 쿼리  (0) 2022.01.26

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);
        }
    }
}

출처 : https://you-rang.tistory.com/269

출처 : https://you-rang.tistory.com/269

출처 : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/linq/introduction-to-linq-queries

출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=herbbread&logNo=90191656950

 

제네릭, 콜렉션

IEnumerable - 스스로 상태(객체접근 횟수)를 저장하지 못해서

타입의 변수를 인풋으로 받았을 때, 다시 처음부터 콜렉션에 접근해서 객체에 접근한다.

 

IEnumerator - 스스로 상태(객체접근 횟수)를 저장함으로

스스로의 상태 state를 기억하고 있다가 다음 호출시, 그 시첨으로 부터

해당 객체를 뱉어낸다?

출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kimsung4752&logNo=220959490816

+ Recent posts