이전 포스팅에 예고한대로 매칭, 제거, 리필 로직에 대해 포스팅하겠습니다.

포스팅은 각 로직에 해당하는 함수를 소개하고, 각 함수에 대해 설명하는 식으로 진행하겠습니다.


1. Match

 생성된 모든 타일에 대해서 매칭을 판별합니다.

    // 모든 타일에 대해 매칭 판별하는 함수
    // 매칭에 해당하는 모든 리스트를 반환한다.
    private int[,] tileArray;
    public List<TileLine> CheckAllMatch()
    {
        List<TileLine> matchLines = new ListList<TileLine>();
        // 좌 -> 우
        matchLines.AddRange(CheckLineMatchAll(HEIGHT,WIDTH,false,new IntVector2(1,0)));
        // 상 -> 하
        matchLines.AddRange(CheckLineMatchAll(WIDTH, HEIGHT, true, new IntVector2(0, 1)));

        return matchLines;
    }
    
    private List<TileLine> CheckLineMatchAll(int line1, int line2, bool isVertical, IntVector2 checkPos)
    {
        List<TileLine> matchLines = new List<TileLine>();
        for (int i = 0; i < line1; i++)
        {
            for (int j = 0; j < line2; j++)
            {
                int count = (isVertical) ? CheckLineMatchFromOneTile(i, j, checkPos) : CheckLineMatchFromOneTile(j, i, checkPos);
                if (count >= 2)
                {
                    TileLine line = new TileLine(isVertical, i, j, j+count);
                    matchLines.Add(line);
                }
                j += count;
            }
        }
        return matchLines;
    }
    // 기준타일로부터 방향(_checkPos)에 같은 타일이 몇개 있는지 반환
    private int CheckLineMatchFromOneTile(int _x, int _y, IntVector2 _checkPos)
    {
        int deltaX = _checkPos.x + _x;
        int deltaY = _checkPos.y + _y;
        int count = 0;
        while (!isOutArray(deltaX, deltaY))
        {
            if (tileArray[_y, _x] == tileArray[deltaY, deltaX])
            {
                count++;
            }
            else
            {
                return count;
            }
            deltaX += _checkPos.x;
            deltaY += _checkPos.y;
        }
        return count;
    }

 위의 함수는 현재 왼쪽 -> 오른쪽, 위쪽 -> 아래쪽으로 타일을 비교하며 3개 이상의 매칭을 판별하고 리턴해줍니다. (코드를 간결하게 짜야하는데...)

 CheckLineMatchFromOneTile 로직은 기준 타일에서 제시된 방향으로 차례로 돌며, 현재 타일이 기준 타일과 동일한 종류의 타일이면 count 갯수를 증가시켜 반환하고, CheckLineMatchAll 에서는 count가 2 이상일 경우 3match로 판단합니다.

 CheckLineMatchFromOneTile 의 경우는 유저의 swap에 따른 4방향 판별에도 사용됩니다.


2. Remove

    // 매칭된 타일을 제거하는 함수
    public void RemoveMatchTile(ref int[,] _tileArray,List<TileLine> _tileLines)
    {
        foreach (TileLine tile in _tileLines)
        {
            IntVector2[] points = tile.GetLinePoints();
            for(int i = 0; i < points.Length; i++)
            {
                _tileArray[points.y,points.x] = -1;
            }
        }
    }

TileLine
    public bool[] GetUseWidthTile(bool[] refillArray)
    {
        if (isVertical)
        {
            refillArray[lineIndex] = true;
        }
        else
        {
            for (int j = startIndex; j <= endIndex; j++)
            {
                refillArray[j] = true;
            }
        }
        return refillArray;
    }

 위의 함수는 매칭된 리스트를 읽어와  -1 ( 빈공간 취급) 으로 값을 변경하고 있습니다. 

 이건 로직은 너무 단순해서... TileLine 즉, 매칭 리스트를 어떻게 저장할 거냐에 따라 달라지겠네요. 저 같은 경우는 가로세로 여부, 라인 번호, 시작 인덱스, 종료 인덱스를 저장하고, 시작~종료까지 공란으로 바꾸는 식으로 진행했습니다.


3. Refill


    // 제거된 타일의 빈공간을 채우는 함수.
    public void RefillTile(ref int[,] _tileArray, List<TileLine> _tileLines)
    {
        // 리필을 할 영역(세로 라인) 표시
        bool[] refillArray = new bool[WIDTH];
        foreach (TileLine tile in _tileLines)
        {
            refillArray = tile.GetUseWidthTile(refillArray);
        }
        //리필 영역에 위에 있는 타일을 내려 빈공간을 채우고, 채우고 남은 최상단 빈 공간의 갯수를 저장한다.
        int[] spaceArray = new int[WIDTH];
        for(int i = 0; i < WIDTH; i++)
        {
            if (refillArray[i])
            {
                int space = 0;
                for(int j = HEIGHT - 1; j >= 0; j--)
                {
                    if(_tileArray[j,i] == -1)
                    {
                        space++;
                    }
                    else
                    {
                        if (space > 0)
                        {
                            _tileArray[j+space,i] = _tileArray[j, i];
                            _tileArray[j, i] = -1;
                        }
                    }
                }
                spaceArray[i] = space;
            }
        }
        // 최상단 빈 공간에 타일을 새로 채운다. 
        for (int i = 0; i < WIDTH; i++)
        {
            if (refillArray[i])
            {
                for (int j = 0; j < spaceArray[i]; j++)
                {
                    if (_tileArray[j, i] == -1)
                    {
                        int index = Random.Range(0, TileCount);
                        _tileArray[j, i] = index;

                    }
                }
                    
            }
        }
       
    }

TileLine
    public IntVector2[] GetLinePoints()
    {
        IntVector2[] points = new IntVector2[endIndex - startIndex +1];
        if (isVertical)
        {
            for (int i = startIndex; i <= endIndex; i++)
            {
                points[i - startIndex].x = lineIndex;
                points[i - startIndex].y = i;
            }
        }
        else
        {
            for (int i = startIndex; i <= endIndex; i++)
            {
                points[i - startIndex].x = i;
                points[i - startIndex].y = lineIndex;
            }
        }

        return points;
    }

 제거된 타일의 빈 공간을 채우는 함수는 세 단계로 이루어집니다.

1. 제거된 빈 공간을 채울 세로 라인 넘버를 저장한다.

2. 저장된 라인 넘버에 대해서 아래부터 위로 차례대로 타일을 내려 빈 공간을 채운다.

3. 빈 공간을 채우고 남은 최상단에 새로운 타일을 넣는다.



상기 코드는 로직만을 구현이 되어있고, 실질적으로 눈에 보이는 것이 없습니다. (오브젝트와 연출) 이 부분은 개별적으로 진행하는 것으로하고, 제가 가장 신경쓰이는 것은 이게 과연 효율적인 로직이냐 입니다.... 오브젝트, 연출까지해서 총 3일이 걸렸는데, 매 코드를 건들 때마다 못미덥네요....ㅠㅠ 쉽게 생각나는 알고리즘은 비효율일 경우가 많아서.. 조금이라도 더 효율적인 로직이 있을거라 생각됩니다. 우선 현재는 이렇게 진행하고, 앞으로는 좀 더 효율적인 로직이 있을지 리서칭을 해보고, 찾는다면 4번째 포스팅에서 로직 개선을 진행하겠습니다. ( 라는 말은 결국 좋은 로직을 찾을 때까지 무기한 연장이라는...)



완성된 후의 VS2015 클래스 다이어그램 (클릭하면 원본 이미지)


 주요 클래스만 설명하자면...

TilePanelModel - 타일들에 대한 로직 담당 (타일 생성,추가,리필 등)

TilePanelView - 타일들의 애니메이션 담당

TileObject - 유저와의 인터렉티브 담당 (클릭 드래그) / 페이즈(Phase) 상태에 따라 행동 위임

ScoreManager - 점수 처리 및 View 담당




* 함수별로 테스트는 완료되었으나 포스트로 옮기는 과정에서 오타가 있을 수 있습니다. 문제 있을시 알려주세요.


* 위 로직 + 오브젝트와 연출의 결과물입니다.














* 지적은 언제나 환영입니다.

Posted by 검은거북

블로그 이미지
프로그래밍 공부 요약 및 공부하며 발생한 궁금증과 해결과정을 포스팅합니다.
검은거북

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.7
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

최근에 올라온 글

최근에 달린 댓글

글 보관함