2018. 4. 24. 01:03 IT/Unity 게임개발
[unity 게임개발] 테트리스 게임 로직 개발 3
회전 로직을 너무 쉽게 생각했었네요.. 생각보다 어려웠습니다. 모든 타일을 왼쪽 상단을 기준으로 배열을 잡으려고 했는데, 막상 그렇게 만들어 놓으니 기존에 보던 테트리스 게임하고 괴리감이 커서 다시 수정을 하고, 그렇게 하니 또 회전 로직이 걸리고...ㅠ 회전 로직이 맘에 좀 안들지만... (다른 분들은 어찌했나 궁금하네요..) 이전 포스팅대로 대부분의 로직은 Block에서 거의 진행을 하고, GameManager는 전체적인 진행과 키입력에 따른 요청을 하고있습니다.
Block의 소스가 중요로직이라고 생각되므로 Block과 키입력 예시부분만 포스팅을 하도록하죱.
1. Block
- 블럭의 이동과 회전을 관리.
public class Block { public int[,,] tile; public Color32 color; int direct; int posX; int posY; public Block(int[,,] _tile, Color32 _color) { tile = _tile; color = _color; } public void SetPostion(int _x,int _y,ref int[,] _map) { int posX = _x; int posY = _y; MoveTile(direct, _x, _y, ref _map); } // 좌우로 움직임을 명령하는 함수. 외부에서 호출 public void MoveHorizon(int _x, ref int[,] _map) { if (CheckTile(_x, _map)) { MoveTile(direct,_x, 0,ref _map); } } // _x,_y 좌표로 이동하는 함수 ( 블럭을 이동시킬 때 사용) void MoveTile(int _direct, int _x, int _y, ref int[,] _map) { for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { if(tile[direct, i, j] == 1) { _map[posY + i, posX + j] = 0; } } } direct = _direct; posX += _x; posY += _y; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (tile[direct, i, j] == 1) { _map[posY + i, posX + j] = tile[direct, i, j]; } } } } // 좌우 좌표로 이동가능한지 확인하는 함수 bool CheckTile(int _x, int[,] _map) { int tempX = posX + _x; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (tile[direct, i, j] == 1 && !(_map[posY + i, tempX + j]==0 || _map[posY + i, tempX + j] == 1)) { return false; } } } return true; } // 블럭을 회전시키고 적용하는 함수. 회전시 맵을 삐져나갈 경우 때문에 새로 확인. public void RotationTile(ref int[,] _map) { // 회전 - 4가 되면 0으로 변경. int tempDirect = (direct +1) & 3; int count = CheckRotation(tempDirect,0, _map); if (count == -10) { return; } else if (count != 0) { // 옆 칸으로 이동해서 재확인. if (CheckRotation(tempDirect, count, _map)==0) { MoveTile(tempDirect, count, 0, ref _map); } }else { MoveTile(tempDirect, 0, 0, ref _map); } } // 블럭이 회전 가능한지 확인하는 함수. 회전했을때 가로로 겹쳐지는 길이를 반환한다. // 겹치는게 없다면 rotation을 하고, 겹쳐진다면 겹쳐진 길이만큼 이동시켜 재확인. // 1,1을 기준으로 왼쪽이 겹치면 +, 오른쪽은 - int CheckRotation(int _direct,int _x,int[,] _map) { int maxLeft = 0; int maxRight = 0; for (int i = 0; i < 4; i++) { int left = 0; int right = 0; for (int j = 0; j < 2; j++) { if (tile[_direct, i, j] == 1) { int tempX = posX + _x + j; if(tempX < 0) { left++; continue; } if (!(_map[posY + i, tempX] == 0 || _map[posY + i, tempX] == 1)) { left++; } } } for (int j =3; j >=2; j--) { if (tile[_direct, i, j] == 1) { int tempX = posX + _x + j; if (tempX >= 12) { right++; continue; } if (!(_map[posY + i, tempX] == 0 || _map[posY + i, tempX] == 1)) { right ++; } } } if (left > maxLeft) { maxLeft = left; } if(right> maxRight) { maxRight = right; } } if(maxRight == 0) { return maxLeft; }else if (maxLeft ==0) { return maxRight * -1; }else { return -10; } } // 블럭의 밑이 고정타일 또는 바닥인지 확인 후 바닥이 아니면 MoveTile을 이용해 내린다. // 바닥이면 applyGround 후 false를 리턴. - GM에서는 라인검색을 할 수 있도록. public bool MoveDown( int[,] _map) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (tile[direct, i, j] == 1 && _map[posY + i+1, posX + j] == -2) { ApplyGround(ref _map); return false; } } } MoveTile(direct,0, 1, ref _map); return true; } // 바닥에 닿은 블럭을 고정타일로 맵에 반영하는 함수. public void ApplyGround(ref int[,] _map) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (tile[direct, i, j] == 1 ) { _map[posY + i, posX + j] = -2; } } } } // 블럭을 바닥으로 한 번에 이동시키는 함수. // 블럭의 밑을 바닥까지 검사하여 가장 적은 거리만큼 이동 시키고 ApplyGround를 한다. public void DropTile(ref int[,] _map) { int min=30; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (tile[direct, i, j] == 1) { int count = 0; while (_map[posY + i + count +1, posX + j] != -2) { count++; } if (count < min) { min = count; } } } } MoveTile(direct,0, min, ref _map); } }
2. 키 입력에 따른 Block함수 사용 예시 ( GameManager의 일부)
if (!isGameOver) { // 버튼 입력에 따른 테트리스 로직 실행. if (Input.GetKeyDown(KeyCode.RightArrow)) { playerBlock.MoveHorizon(1, ref map); } if (Input.GetKeyDown(KeyCode.LeftArrow)) { playerBlock.MoveHorizon(-1, ref map); } if (Input.GetKeyDown(KeyCode.UpArrow)) { playerBlock.RotationTile(ref map); } if (Input.GetKeyDown(KeyCode.DownArrow)) { if (playerBlock.MoveDown(map) == false) { // 라인을 탐색하여, 가득차면 제거 // 천장을 넘어가면 게임 종료. // 새로운 블럭생성. } } if (Input.GetKeyDown(KeyCode.Space)) { playerBlock.DropTile(ref map); playerBlock.ApplyGround(ref map); // 라인을 탐색하여, 가득차면 제거 // 천장을 넘어가면 게임 종료. // 새로운 블럭생성. } }
* 아래 동영상은 완성본의 일부 영상입니다.
* 지적은 언제나 환영입니다.
'IT > Unity 게임개발' 카테고리의 다른 글
[게임 개발]도시경영 전략 게임 로직 만들기 - 1 (0) | 2018.06.15 |
---|---|
[unity] 구글 플레이 연동 및 파이어 베이스 사용기 (환경 및 오류 위주) (1) | 2018.05.01 |
[unity 게임개발] 테트리스 게임 로직 개발 2 (0) | 2018.04.23 |
[unity 게임개발] 테트리스 게임 로직 개발 1 (0) | 2018.04.22 |
[unity 게임개발] 지렁이 키우기 로직 개발 3 (0) | 2018.04.18 |