Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Archives
Today
Total
관리 메뉴

For me

[Unity] 4) Block Match 본문

Unity/3Match

[Unity] 4) Block Match

GiveZero 2023. 2. 20. 16:34

1. 처음에는 BFS로 탐색해서 Match 하려고 했지만, T , L , 5칸 등 너무 많은 다른 모양으로 구현이 쉽지 않았음

 

2. 그럼 어떤걸 로 해야하나? 

다음과 같이 숫자 순서대로 탐색하여 모양을 찾음.

매치 된다면 2진수로 값을 더하면 겹치는 수 없이 모든 Board 탐색 가능

 

만약 2,0,중앙 이 Match가 된다면?

1 + 4 + 0 = 5

 

7,3,1,5,0 으로 5줄 Match가 된다면?

128 + 8 + 2 + 32 = 170

 

이후, 모양에 맞는 모든 case를 switch문을 통해 처리할 수 있다.

T, L , 4 , 5 , 사각형 등 모든 모양에 대해 처리할 수 있다.

    bool Find3Match(Block b, ref int[,] countBoard, BFSMode mode)
    {
        int x = b.X;
        int y = b.Y;
        bool isMatch = false;
        int mask = 0;
        List<BlockController> matchList = new List<BlockController>();

        for (int i = 0; i < 4; i++)
        {
            bool isMatch2 = false;
            int rx = x + dx[i];
            int ry = y + dy[i];

            int rx2 = x + dx[(i + 2) % 4]; // rx의 반대방향
            int ry2 = y + dy[(i + 2) % 4];

            int rx3 = x + dx[i+4]; // rx 보다 한칸 더
            int ry3 = y + dy[i+4];

            if (rx >= 0 && rx < WIDTH && ry >=0 && ry < HEIGHT && board._blocks[rx + ry * HEIGHT].info.colorType == b.colorType)
            {
                // rx 반대칸 (L 으로 매칭되면 안되므로 반대쪽 체크)
                if (rx2 >= 0 && rx2 < WIDTH && ry2 >= 0 && ry2 < HEIGHT && board._blocks[rx2 + ry2 * HEIGHT].info.colorType == b.colorType)
                {
                    isMatch2 = true; 
                }

                // rx 다음 칸
                if (rx3 >= 0 && rx3 < WIDTH && ry3 >= 0 && ry3 < HEIGHT && board._blocks[rx3 + ry3 * HEIGHT].info.colorType == b.colorType)
                {
                    matchList.Add(board._blocks[rx3 + ry3 * HEIGHT]);
                    countBoard[rx3, ry3]--;
                    mask |= 1 << (i + 4);
                    isMatch2 = true;
                }


                if(isMatch2)
                {
                    isMatch = true;
                    matchList.Add(board._blocks[rx + ry * HEIGHT]);
                    countBoard[rx, ry]--;
                    mask |= 1 << i;
                }
            }
        }

        if(isMatch)
        {
            countBoard[x, y]=0;
            if (mode == BFSMode.Match)
                MatchBlock(mask, b, matchList);
           
            else if(mode == BFSMode.SUFFLE)
                SuffleBoard(board._blocks[x + y * HEIGHT]);

            return true;
        }
        
        return false;
    }

 

하지만

 

블럭들은 한번에 처리해야 하고, 처리해야 할 순서가 다르다.

 

T , L 을 먼저 처리하고 5, 4, 3 순으로 처리하지 않으면 안된다. 만약 이렇게 처리하지 않게 된다면 3칸으로 항상 처리될것이다.

 

따라서,  TL - 5 - 사각형 - 4 - 3 순으로 처리를 하도록 한다.

 

모든 블럭을 탐색하면서 각 블럭과 이어져 있는 블럭이 (자신 포함) 3개 이상일 시 maskingBoard에 + 1 

    bool InitBoardMatch(BFSMode mode = BFSMode.Match)
    {
        bool isMatch = false;
        int[,] countBoard = new int[9, 9];
        int[,] count2x2Board = new int[9, 9];

        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                if (board._blocks[i + j * HEIGHT].info.blockType == BlockType.EMPTY || board._blocks[i + j * HEIGHT].info.blockType == BlockType.NEVER) continue;

                if (GetVerticalBlockCount(board._blocks[i + j * HEIGHT].info) > 2)
                    countBoard[i, j]++;
                if (GetHorizontalBlockCount(board._blocks[i + j * HEIGHT].info) > 2)
                    countBoard[i, j]++;
                if (GetVerticalBlockCount(board._blocks[i + j * HEIGHT].info) > 1)
                    count2x2Board[i, j]++;
                if (GetHorizontalBlockCount(board._blocks[i + j * HEIGHT].info) > 1)
                    count2x2Board[i, j]++;
            }
        }

        // ㄴ , ㅜ 검사
        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                if (countBoard[i, j] == 2)
                {
                    if(Find3Match(board._blocks[i + j * HEIGHT].info, ref countBoard, mode))
                        isMatch = true;
                }
            }
        }

        for(int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                if(countBoard[i, j] == 1 && Find5Match(board._blocks[i + j * HEIGHT].info, ref countBoard, mode))
                    isMatch = true;
                if(count2x2Board[i, j] == 2 && Find2X2Match(board._blocks[i + j * HEIGHT].info, ref countBoard, ref count2x2Board, mode))
                    isMatch = true;
                if(countBoard[i, j] == 1 && Find4Match(board._blocks[i + j * HEIGHT].info, ref countBoard, mode))
                    isMatch = true; 
                if(countBoard[i, j] == 1 && Find3Match(board._blocks[i + j * HEIGHT].info, ref countBoard, mode))
                    isMatch = true;
            }
        }


        return isMatch;
    }


int GetVerticalBlockCount(Block b)
    {
        int count = 0;
        for(int i = b.Y - 2; i <= b.Y + 2; i++)
        {
            if (i < 0) continue;
            if (i >= HEIGHT) break;

            if (b.colorType == board._blocks[b.X + i * HEIGHT].info.colorType)
                count++;
        }
        return count;
    }

    int GetHorizontalBlockCount(Block b)
    {
        int count = 0;
        for (int i = b.X - 2; i <= b.X + 2; i++)
        {
            if (i < 0) continue;
            if (i >= WIDTH) break;

            if (b.colorType == board._blocks[i + b.Y * HEIGHT].info.colorType)
                count++;
        }
        return count;
    }

 

이와 같이 한다면,

L자나 T자는 다음과 같이 2인 블럭부터 탐색하게 된다면 처리가능

T와 L 형, 5칸 을 처리후에 4칸을 체크하기위한 count2X2Board 배열을 이용해서 따로 체크

 

    void MatchBlock(int mask, Block b, List<BlockController> matchList)
    {
        ColorType color = board._blocks[b.X + b.Y * HEIGHT].info.colorType;
        switch (mask)
        {
            // 1
            case 0:                
                break;
            // 2
            case 1:case 2:case 4:case 8:
                break;


            // 3
            case 5:case 10:case 17:case 34:case 68:case 136:
                MatchAnimStart(board._blocks[b.X + b.Y * HEIGHT]);
                ListMatchAnimStart(matchList);
                break;

            // 4 Horizontal Line Clear
            case 21:case 69:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[b.X + b.Y * HEIGHT], PieceType.HorClear, color);
                break;

            // 4 Vertical Line Clear
            case 42:case 138:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[b.X + b.Y * HEIGHT], PieceType.VerClear, color);
                break;

            // 5 Rainbow Hor
            case 85:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[(b.X + 2) + b.Y * HEIGHT], PieceType.RainBow, ColorType.None);
                break;

            // 5 Rainbow Ver
            case 170:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[b.X + (b.Y + 2) * HEIGHT], PieceType.RainBow, ColorType.None);
                break;

            // 4X3 Bomb
            case 55: case 59: case 110: case 133: case 155: case 157: case 205:case 206:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[b.X + b.Y * HEIGHT], PieceType.Bomb, color);
                break;

            // ㄱ ㄴ .. Bomb
            case 51:case 102:case 153:case 204:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[b.X + b.Y * HEIGHT], PieceType.Bomb, color);
                break;

            // ㅏ ㅓ ㅗ ㅜ Bomb
            case 27:case 39:case 94:case 141:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[b.X + b.Y * HEIGHT], PieceType.Bomb, color);
                break;

            case 265: case 515: case 1054: case 3108:
                ListMatchAnimStart(matchList);
                PieceMake(board._blocks[b.X + b.Y * HEIGHT], PieceType.Munchkin, ColorType.None);
                break;
        }   
            
        
    }

매칭된 블럭은 다음과 같이 모든 케이스에 대해서 처리

'Unity > 3Match' 카테고리의 다른 글

[Unity] 6) Block Respawn  (0) 2023.02.20
[Unity] 5) Block Down  (0) 2023.02.20
[Unity] 3) Input / 블럭 Swap  (0) 2023.02.19
[Unity] 2) Block , Cell 배치 (초기화)  (0) 2023.02.16
[Unity] 1) 3Match 구성  (0) 2023.02.16