For me
[Unity] 4) Block Match 본문
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 |