강의 정리

[Unity] [르탄이 카드 뒤집기] 카드 앞면 이미지를 랜덤으로 넣어주기

lhgenol 2025. 2. 3. 22:17

카드 만들기 - 이미지 랜덤 로직(4-4)

카드 앞면 이미지를 랜덤으로 넣어주기

  • 이번에는 배치된 카드의 앞면에다가 이미지들을 넣어주자.
  • 그런데 그냥 넣는 게 아니라 판이 시작될 때마다 섞어줘서 그때그때 다른 조합, 순서로 넣어줘야 함.
  • 카드 리스트를 만들고, 그 리스트를 섞고, 카드가 만들어 질 때 하나씩 꺼내서 르탄이 이미지를 붙여주자.
  • Board 스크립트로 가보자.
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
  • 리스트는 int, 정수형을 쓴다.
  • 짝이 맞는 카드들이니 0부터 7까지 리스트를 작성한다.
  • 정확하게는 int에 대괄호를 적어주면 리스트가 아니라 배열이라고 불려지게 됨. 동일한 자료형들이 여러 개 들어갈 수 있는 것이 바로 배열. 크기는 정해져 있어서 처음에 정해진 이 크기, 숫자만큼만 사용할 수 있다.
  • 그리고 이 데이터를 몇 번째 데이터로 할건지 접근도 가능하다.
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr[4];
  • 예를 들어 arr[4];라고 하면, '네 번째에 있는 데이터를 가져와라'가 됨. 0부터 세니까 네 번째 네이터는 2.
  • 이런 특성을 이용해 랜덤으로 섞어주고, 숫자가 0번부터 15번까지 늘어나니까 마지막 15번째 순서에 있는 데이터까지 꺼내와 주는 걸로 로직을 작성해 보자.
  • 그러면 먼저 이 배열을 섞어줘야 한다.
using System.Linq;

public class Board : MonoBehaviour
{
    public GameObject card;

    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();
  • 코드 작성을 위해 using문 하나를 작성. System.Linq. Linq라고 하는 새로운 기능을 써볼 것임.
  • 하나하나 코드를 살펴보자.
  • arr에서 .을 눌렀으니 배열에서 쓸 수 있는 어떤 기능이라는 뜻이고 OrderBy는 정렬한다는 뜻
  • 정렬할 건데 어떻게 정렬할 건지 다음 소괄호 안에 조건이 들어간 것
  • =>는 이 배열을 순서대로 한 번씩 순회한다는 뜻
  • 그리고 중요한 건 배열을 지정해 주는 건데 그 기준값이 Random.Range에서 추출된 값. 그때그때 다를테니 예를 들어 x가 처음에 0번째로 갔을 때 Random.Range가 한번 실행되겠지? 그러면 0에서 7 사이에 어떤 임의의 값이 나올 텐데 그 값을 기준으로 작거나 크다, 또 얼만큼 작고 얼만큼 큰지에 따라서 우선순위가 나뉘게 된다. 그 우선순위에 따라서 정렬을 해 주게 되는 것. 다음 0번으로 갔을 때는 또 다른 값이 나오겠지? 그러면 앞선 값보다 크거나 작거나 할 수 있고 그 정도도 다를 것. 그 기준을 정해주는 게 바로 이 Random.Range.
  • 이 값과 순차대로 접근하는 값을 비교해서 우선순위를 두고 정렬한다고 생각하면 됨
  • 그렇게 정렬해 주고 ToArray, 배열. '배열로 만들어 준다'라고 한 번 더 적어줘야 됨
  • OrderBy를 썼는데 현재 자료형이 Array가 아니기 때문에 Array로 바꿀 수 있게끔 ToArray로 맞춰주는 것
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();
  • ToArray를 사용해 배열로 바꿔줬다면, 이걸 기존의 배열에다가 다시 넣어 줘야 하기에 arr = 추가 작성
  • 이렇게 되면 이제 랜덤한 값들이 섞여서 다시 재배열 됐을 것.
  • 0번부터 15번까지 순차대로 확인을 해봐야 되니까 반복문 안에다가 적어주자. (반복문이 i값이 0번부터 15번까지 가니까)
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();

        for(int i = 0; i < 16; i++)
        {
            GameObject go = Instantiate(card, this.transform);

            float x = (i % 4) * 1.4f - 2.1f;
            float y = (i / 4) * 1.4f - 3.0f;

            go.transform.position = new Vector2(x, y);
            Debug.Log(arr[i]);
        }
    }
  • 디버그 로그를 작성해 제대로 섞였는지 한번 확인해 보자.
  • arr에 대괄호를 쓰면 배열의 몇 번째 값에 접근할 거냐는 뜻.
  • 플레이하고 콘솔창을 보면, 랜덤하게 값들이 재배열됐다.
  • 그리고 다시 실행했을 때 지금과 다른 순서대로 다시 배열이 되어 있어야 한다.
  • 다시 플레이 해보면, 플레이할 때마다 순서가 바뀌어서 정렬되어 있는 걸 볼 수 있다.
  • 이제 이 랜덤한 값들을 각각의 카드에다가 넣어주면 되겠다. 그러기 위해 Card 스크립트 생성. Card Prefab에도 스크립트 적용
  • Card 스크립트 ㄱㄱ
public class Card : MonoBehaviour
{
    int idx = 0;
  • 각각의 카드에다가 랜덤하게 섞인 값들을 하나하나 넣어줄 것. 그러면 그 값을 받아줄 수 있는 변수를 하나 만들어 줘야한다.
  • int idx(index) 변수를 적어준다. 초깃값은 0으로 세팅.
  • 그리고 이 idx, 인덱스 번호를 세팅할 수 있는 함수를 하나 만들어 주자.
    public void Setting()
    {

    }
  • 외부에서 접근할 수 있는 함수를 Update 아래에 작성. 그리고 매개변수를 하나 만들어 주자. 매개변수를 쓰면 외부에서 setting이라는 함수를 호출할 때 어떤 값을 넣어줄 수 있게 된다.
    public void Setting(int number)
    {
        idx = number;
    }
  • int number라고 써주고, 이 number를 idx라고 하는 변수에다가 넣어주면 되겠다.
  • 예를 들어 리스트가 한번 섞였다고 가정해 보자. 배열의 첫 번째 수가 7이라고 하면 첫 번째로 생성된 카드에다가, 이 setting 함수에다가 7을 넣어주고 그 7이 첫 번째 카드의 idx에 들어가게 되는 것. (idx = number;를 통해)
  • 그러면 이 값들이 제대로 들어가는지 확인해 보자. 그러기 위해서는 세팅할 때 카드에다가 번호를 넣어줘야 한다.
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();

        for(int i = 0; i < 16; i++)
        {
            GameObject go = Instantiate(card, this.transform);

            float x = (i % 4) * 1.4f - 2.1f;
            float y = (i / 4) * 1.4f - 3.0f;

            go.transform.position = new Vector2(x, y);
            Debug.Log(arr[i]);
        }
    }
  • Board 스크립트로 가서, 지난 시간에 생성된 게임 오브젝트에 대한 정보를 go라는 변수에다가 넣어줬었다.
  • 우리는 이 go에 있는 컴포넌트를 가져와야 한다. Card라고 하는 스크립트를 가져와야 한다.
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();

        for(int i = 0; i < 16; i++)
        {
            GameObject go = Instantiate(card, this.transform);

            float x = (i % 4) * 1.4f - 2.1f;
            float y = (i / 4) * 1.4f - 3.0f;

            go.transform.position = new Vector2(x, y);
            go.GetComponent<Card>()
        }
    }
  • 어떤 컴포넌트, 어떤 스크립트를 가져오기 위해서는 GetComponent 키워드 사용.
  • Card라는 스크립트를 만들어줘서 컴포넌트로 붙였기 때문에 찾을 수 있게 되는 것
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();

        for(int i = 0; i < 16; i++)
        {
            GameObject go = Instantiate(card, this.transform);

            float x = (i % 4) * 1.4f - 2.1f;
            float y = (i / 4) * 1.4f - 3.0f;

            go.transform.position = new Vector2(x, y);
            go.GetComponent<Card>().Setting()
        }
    }
  • 이 Card라고 하는 스크립트, Card라고 하는 컴포넌트 안에 있는 Setting이라는 함수를 불러오는 것
    void Start()
    {
        int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
        arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();

        for(int i = 0; i < 16; i++)
        {
            GameObject go = Instantiate(card, this.transform);

            float x = (i % 4) * 1.4f - 2.1f;
            float y = (i / 4) * 1.4f - 3.0f;

            go.transform.position = new Vector2(x, y);
            go.GetComponent<Card>().Setting(arr[i]);
        }
  • 여기에다가 우리는 배열(arr)의 i번째에 있는 데이터를 넘겨주는 것
  • 예를 들어 i가 0일 때는 0번째에 있는(섞이기 전엔 0이니) 0을 Setting에 넘겨주게 되는 것. 그러면 Card 스크립트에서는 int number 매개변수를 통해 넘어온 0을 idx에다가 넣어주게 된다.
  • 예를 들어 for문에서 쭉 진행을 해서 i가 7이 됐을 때, 배열의 7번째 즉 3이라는 값이 Setting이라는 함수를 통해서 Card 스크립트로 넘어감 -> Card에서 매개변수로 넘어온 3이라고 하는 값이 idx라고 하는 변수에 들어감
  • 플레이 해보면 카드들이 세팅됐다. Card를 클릭해 보면 idx 정보를 확인할 수 없음. public으로 설정을 안 해줘서 그럼. 그럴 때는 Inapector라고 하는 글씨 위에서 오른쪽 마우스를 눌러 Debug를 눌러주면 idx값이 보인다.
  • 다시 플레이 해서 Card를 클릭해 보면 각각의 idx 정보가 적힌 걸 볼 수 있다. 이렇게 랜덤한 값들이 잘 들어갔다.
  • 이번에는 이 숫자를 가지고 르탄이 이미지들을 불러와 줘야 한다.
  • 첫 번째 카드가 5라는 값을 받았다면 rtan5 이미지를 받아오게끔 코드를 짜주자.
  • Images 폴더에서 코드를 통해서 받아올 건데, Assrts 안 Images 폴더에서 가지고 오는 방법은 여러가지가 있지만 이번에는 Resources 폴더라고 하는 것을 활용해 보자.
  • Resources 폴더를 만들고, 여기에 르탄이 이미지들을 모두 옮겨주자.
  • 다시 Card 스크립트로 돌아가자. 넘겨받은 idx를 기반으로 르탄이 이미지들을 가져오면 되겠다.
  • 이미지를 가져오기 위해 Resources를 적어보자.
    public void Setting(int number)
    {
        idx = number;
        Resources.Load<>
    }
}
  • Load의 꺽쇠에는 자료형이 들어간다. 그럼 르탄이의 자료형은 뭘까?
  • 유니티로 가서 르탄이 이미지를 보면 Texture Type이 Sprite라고 되어 있다. Sprite로 받아오면 되겠다.
    public void Setting(int number)
    {
        idx = number;
        Resources.Load<Sprite>("")
    }
  • 자료형을 Sprite로 넣고, 소괄호 안에다가는 경로를 적어준다.
  • Resources 폴더 안에 바로 넣었으니 우리는 르탄이 파일명만 제대로 넣어주면 된다.
    public void Setting(int number)
    {
        idx = number;
        Resources.Load<Sprite>("rtan")
    }
  • 일단 rtan은 넣었는데 추가로 idx를 넣을 함수가 딱히 없는 것 같다.
  • 이럴 때 String값을 조작하는 한 가지 기능을 알아보자.
    public void Setting(int number)
    {
        idx = number;
        Resources.Load<Sprite>($"rtan{idx}");
    }
  • 바로 달러($) 표시
  • 쌍따옴표 앞에 $를 적고 rtan 뒤에 중괄호를 적어주는 것
  • 중괄호 안에다가 idx라고 적어준다. 중괄호 안은 변수(idx)를 쓸 수 있다.
  • 예를 들어 number에 3이 넘어와서 idx에 3이 들어갔다면, 중괄호 안에도 3이 들어가니까 문자열에 rtan3이라고 들어가는 것
  • 이런 기능을 통해서 그때그때 다양한 이름, 다양한 문자 형식에 대해 대응할 수가 있다.
  • 이제 이 받아온 값을 Front에 넣어줘야 한다.
public class Card : MonoBehaviour
{
    public SpriteRenderer front;
  • 이미지를 넣어주기 위해 SpriteRenderer로 받아온다.
    public void Setting(int number)
    {
        idx = number;
        front.sprite = Resources.Load<Sprite>($"rtan{idx}");
    }
  • 그리고 front 안에 Resources.Load를 넣어준다.
  • 그 다음 유니티로 돌아가서 Card Prefab의 Front를 Card 스크립트의 Front 변수에 넣어준다.
  • 플레이 해보면... 안뜬다.
  • 안떠!!!!!!!!!!!
  • 하... 자고 일어나서 다시 해보자.

  • 굿모닝.. 수정했다.
  • 두 가지 문제가 있었다. 첫 번째는 인스펙터 창을 normal이 아닌 debug로 해놔서 강의 화면과 세팅값들이 달라 혼돈이 왔던 것이고, 두 번째는 그 혼돈이 오고 넋이 나가서 오타가 있나 찾아보다 정작 괄호는 신경쓰지 않았던 것이다.
($"rtan{idx}")
  • 이거를 ($"rtan[idx]")라고 적어서 생긴 문제..ㅎㅎ
  • 아무튼 이렇게 Resources 폴더와 코드를 사용해 랜덤한 값에 랜덤한 이미지를 넣어줬다.