내일배움캠프(Unity)

내일배움캠프 게임개발(Unity) 사전캠프 16일차 TIL

빵어 2023. 10. 23. 20:52

사천성 만들기

1. 두 카드가 연결 가능한지 확인하기

두 카드가 같은 카드일 때 삭제되는 것을 구현했으니

이제 두 카드가 사천성 규칙에 따라 연결 가능한지 확인해야할 차례이다.


- 두 카드의 연결선이 3번 이상 꺾이면 안된다.

- 두 카드는 빈 공간에서만 연결된다.

 

 

분명 오늘 계획은 적절한 알고리즘을 이용해 구현을 하는 것이었지만

bfs, 다익스트라 등 아직 알고리즘에 익숙하지 않은 나에게 응용은 너무 큰 꿈이었다.

그래서 일단 구현에 초점을 맞추고 코드를 작성했다.

 

 

일단 구현의 편의성을 위해 CardManager를 GameManager와 합쳤다.

 

그리고 Start문에서 Shuffle한 카드들을 position에 따라 정렬했다.

그런 다음 각 카드마다 순서대로 number를 부여했다.

이 number로 카드가 어디에 위치해있는지 알아낼 것이다.

private void Start()
{
    cardList = new List<GameObject>();

    CreateCards();
    ShuffleCards();

    cardList = cardList.OrderBy(o => o.transform.position.y)
        .ThenBy(o => o.transform.position.x)
        .ToList();

    for (int i = 0; i < cardList.Count; ++i)
        cardList[i].GetComponent<Card>().cardNum = i;
}

 

연결될 수 있는 카드가 있는지 확인하는 IsCardConnected() 함수와 CheckCardConnectionRecursive()(재귀함수)를 구현했다. (미완성, 오류 많음)

bool IsCardConnected()
{
    int turnCount = 0;

    //Vector3 dir = secondCard.transform.position - firstCard.transform.position;

    // first카드부터 출발해서 second카드까지
    int dirNum = -1;
    int tempCardNum = firstCard.GetComponent<Card>().cardNum;
    bool[] visited = new bool[cardList.Count];

    return CheckCardConnectionRecursive(turnCount, visited, tempCardNum, dirNum);
}

// 오른쪽에서 왼쪽은 되는데 왼쪽에서 오른쪽은 안됨
bool CheckCardConnectionRecursive(int turnCount, bool[] visited, int tempCardNum, int dirNum)
{
    int[] dx = { 0, 0, -1, 1 };
    int[] dy = { 1, -1, 0, 0 };

    for (int i = 0; i < dx.Length; ++i)
    {
        int nx = tempCardNum % xCount + dx[i];
        int ny = tempCardNum / yCount + dy[i];

        tempCardNum = tempCardNum + dx[i] + (dy[i] * xCount);

        if (tempCardNum < 0 || tempCardNum >= cardList.Count
            || nx < 0 || nx >= xCount
            || ny < 0 || ny >= yCount)
            continue;

        // 방향이 지금까지와 다르다면 ++turnCount
        if (dirNum != i)
        {
            ++turnCount;
            if (turnCount > 3)
            {
                --turnCount;
                continue;
            }

            dirNum = i;
        }

        // secondCard와 같은 자리라면 true
        if (tempCardNum == secondCard.GetComponent<Card>().cardNum)
            return true;

        // 카드가 있는 자리라면
        if (cardList[tempCardNum].activeSelf)
            continue;

        // 방문한 자리라면
        if (visited[tempCardNum])
            continue;
        visited[tempCardNum] = true;

        CheckCardConnectionRecursive(turnCount, visited, tempCardNum, dirNum);
    }

    return false;
}

재귀함수의 이름이 긴데, 뭐라 지어야할지 감이 안잡혀서 ChatGPT한테 물어봤다..

 

 

Update문에서 두 카드의 Sprite를 비교하는 부분에 IsCardConnected()함수를 조건으로 넣어줬다.

그리고 Destroy대신 SetActive(false)로 삭제된 것처럼 보이도록 했다.

if (firstCard.GetComponent<Card>().spriteNum
    == secondCard.GetComponent<Card>().spriteNum
    && IsCardConnected())
{
    firstCard.SetActive(false);
    secondCard.SetActive(false);

    firstCard = null;
    secondCard = null;
}

 

지금 프로그램을 실행시키면 정말 느리고 잘 작동이 되지 않는다.

붙어있는 카드 중 오른쪽 카드를 먼저 클릭하고 왼쪽 카드를 클릭하면 카드가 잘 제거되지만 반대는 제거되지 않는다.

같은 맥락으로 위 -> 아래는 제거되지 않지만 아래->위는 제거된다.

그리고 떨어져 있는 카드도 제거되지 않는다.

 

내일 다시 손보는 걸로~

 

최적화도 게임이 완성되고 사전캠프 기간이 남으면 손봐야겠다.