[Unity3D] 헥사게임 만들기 세 번째 - 블럭처리2.
※ 소스 출처 : 네이버 카페 - 유니티 허브 - 햐얀바람님.
0. 리소스 준비하기.
1). 배경 이미지.
2). 블럭보드의 배경 이미지.
3). UI테두리 이미지.
4). 블럭 이미지.
1. 캔버스 크기 설정하기.
- 게임뷰어 및 캔버스 크기 설정.
2. 블럭보드 만들기.
1). 블럭 프리팹 만들기.
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 | // 매치된 블럭 삭제하기. void BlockDelete() { // 매치된 블럭이 생겨 빈 공간이 생겼는지 판단하는 플래그. bool bMatch = false; GameObject[] blocks = GameObject.FindGameObjectsWithTag("BLOCK"); foreach (GameObject block in blocks) { Block sBlock = block.GetComponent<Block>(); if (sBlock.bDead) { // 삭제된 블럭 칸의 을 -1로. BlockBoard[sBlock.iX][sBlock.iY] = (int)BLOCK.BLANK; Destroy(block); bMatch = true; } } // 빈 공간이 생겼을 경우. if (bMatch) BlockDown(); } | cs |
블럭삭제 함수안에 bool 변수인 bMatch가 새로 추가되었습니다.
이 변수의 초기값은 false로 하는 일은 삭제된 블럭이 하나라도 있는가 판단하는 일입니다.
bMatch가 true가 된다면 삭제한 블럭이 있다는 것이며, 삭제된 블럭이 있던 공간은 빈 공간이 됩니다.
빈 공간이 생겼을 경우 블럭은 떨어져야 합니다.
즉, 변수 bMatch는 BlockDown()함수를 호출 할 것인지 하지 않을것인지 판단하는 재료가 됩니다.
4). 떨어지는 블럭 함수 만들기.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | void BlockDown() { bool bBlockDown = false; for (int x = 0; x < iBlockX; x++) { bool BlankCheck = false; for (int y = iBlockY - 1; y > -1; y--) { // x,y의 위치에 블럭이 비어있다면. if (!BlankCheck && BlockBoard[x][y] == (int)BLOCK.BLANK) { BlankCheck = true; bBlockDown = true; //--------- (x, iBlockY) 위치에 블럭 생성.------------- GameObject block = Instantiate(OriginBlock, new Vector3(x, iBlockY, 0), Quaternion.identity); block.transform.SetParent(transform); int iType = Random.Range(0,BlockType.Length); Block sBlock = block.GetComponent<Block>(); sBlock.iX = x; sBlock.iY = iBlockY; sBlock.iType = iType; sBlock.SetBlockImg(BlockType[iType]); //----------------------------------------------------- // 블럭을 내리기 위한 위치 셋팅. for (int z = y + 1; z < iBlockY+1; z++) { GameObject[] blocks = GameObject.FindGameObjectsWithTag("BLOCK"); foreach (GameObject block2 in blocks) { sBlock = block2.GetComponent<Block>(); if (sBlock.iX == x && sBlock.iY == z) { sBlock.StartPos = new Vector3(x, z, 0); sBlock.TartgetPos = new Vector3(x, z - 1, 0); sBlock.bDown = true; break; } } } } } } if (bBlockDown) bBlockMoveDown = true; else StartCoroutine(BlockCheck()); } | cs |
1 | bool bBlockDown = false; | cs |
bool 변수은 bBlockDown변수가 하는 일은 블럭이 떨어져야 하느냐 판단하는 일입니다.
즉, 이 변수가 true가 된다면 모종의 셋팅이 된 블럭들을 떨어뜨리는 겁니다.
1 2 3 4 5 6 7 | for (int x = 0; x < iBlockX; x++) { bool BlankCheck = false; for (int y = iBlockY - 1; y > -1; y--) { } } | cs |
2중 for문은 블럭보드를 검사하는 구문입니다.
첫 번째 for문은 x값으로 열에 해당됩니다.
2번째 for문은 행에 해당됩니다.
초기값으로 iBlockY - 1인 이유는 밑에서 위로 검사하는 것이 아닌 위에서 아래 순서로 검사하기 위해서 입니다.
※ iBlockY변수는 블럭보드의 높이(블럭의 세로 개수) 입니다.
iBlockY 변수에 - 1을 한 이유는 제로(0)베이스 이기 때문입니다.
이렇게 높이를 1씩 감소시키면서 빈 공간을 찾아 한 줄을 검사 합니다.
그림으로 보자면 다음과 같은 줄만을 검사 합니다.
x값이 1 증가한다면 밑과 같이 검사 하겠군요.
첫 번째 for문과 두 번째 for문 사이에 있는 bool 변수 BlankCheck는 현재 검사하고 있는 줄에서
빈 공간이 있을 때 블럭을 한 번만 만들어 주기 위한 플래그 입니다.
검사하고 있는 줄에서 빈 칸이 2개 이상일 때, 이 플래그가 없다면 빈칸의 숫자만큼 한 번에 블럭을 만들어 주게 됩니다.
블럭의 위치를 이용하고 있는 상황에서 같은 위치에 한 번에 여러개의 블럭을 만든다는 것은 좋지 않은 일입니다.
1. 빈칸을 찾으면 하나의 블럭을 만든다.
2. 블럭들을 움직인다.
3. 다시 빈칸을 찾는다.
즉, 함수 한 번 호출당 한 줄, 한 빈칸에 블럭을 하나씩 생성해주고 한 칸씩만 이동한다고 생각하시면 됩니다.
다음 빈 칸을 채우는 것은 다음 함수가 호출될 때 입니다.
1 2 3 | if (!BlankCheck && BlockBoard[x][y] == (int)BLOCK.BLANK) { } | cs |
조건문입니다. 현재 BlockBoard[x][y] == 빈칸이냐?
라는 뜻이군요.
이 조건을 클리어 하면 2개의 플래그를 모두 true로 바꿔줍니다.
1 2 | BlankCheck = true; bBlockDown = true; | cs |
설명은 bool값 선언 부분에서 말 한것이 전부 입니다.
1 2 3 4 5 6 7 8 9 10 | GameObject block = Instantiate(OriginBlock, new Vector3(x, iBlockY, 0), Quaternion.identity); block.transform.SetParent(transform); int iType = Random.Range(0,BlockType.Length); Block sBlock = block.GetComponent<Block>(); sBlock.iX = x; sBlock.iY = iBlockY; sBlock.iType = iType; sBlock.SetBlockImg(BlockType[iType]); | cs |
빈 칸에 따른 새로운 블럭 생성 구문 입니다.
Instantiate(원본 프리팹, 위치, 회전상태) 함수로 새로운 블럭을 만들어 줍니다.
* new Vector3(현재 검사하고 있는 열, 열의 높이, 0)
블럭을 새로 생성시켰기 때문에 그 블록이 가진 정보들 여러가지를 초기화 시켜야 합니다.
1. 현재 블럭의 위치 값.
2. 현재 블럭의 타입.
3. 현재 블럭의 타입에 따른 이미지.
등을 초기화 시킵니다.
블럭을 새롭게 만들어 정보를 셋팅 시켰으니 다음은 블럭을 떨어뜨릴 차례입니다.
1 | for (int z = y + 1; z < iBlockY+1; z++) | cs |
이 구문의 뜻은 대략 이렇습니다.
z = y + 1
현재 y의 위치는 빈 칸입니다.
빈칸의 + 1칸은 빈 칸의 바로 윗 칸이 되겠군요.
빈 칸의 바로 윗칸(y + 1) 부터 블럭이 새롭게 생성된 위치의 칸 까지(iBlockY + 1) 포함해 모두 떨어뜨려야 합니다.
1 | if (sBlock.iX == x && sBlock.iY == z) | cs |
현재 검사하고 있는 블럭의 위치가 위 그림의 파란색 칸 위치의 블럭과 같다면.
1 2 3 4 | sBlock.StartPos = new Vector3(x, z, 0); sBlock.TartgetPos = new Vector3(x, z - 1, 0); sBlock.bDown = true; break; | cs |
1라인 == 파란색 칸의 위치
2라인 == 노랜색 칸의 위치
로 셋팅.
이렇게 셋팅된 위치를 토대로 블럭을 TargetPos까지 이동 시킨다.
3라인 == 이동을 허가하는 플래그 변수 (bDown)
여기서 일단 Block 스크립트로 넘어갑시다.
왜냐하면 3라인 에서 블럭 이동에 대한 허가가 내려왔기 때문입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | private float fStep = 0f; // 속력 축적 변수. private float fMoveSpeed = 10f; // 블럭 떨어지는 기본 속력. void Update() { if (bDown && transform.position != TartgetPos) { fStep += Time.deltaTime * fMoveSpeed; transform.position = Vector3.MoveTowards(StartPos, TartgetPos, fStep); if (transform.position == TartgetPos) { int X = (int)TartgetPos.x; int Y = (int)TartgetPos.y; gMar.BlockBoard[X][Y] = iType; iX = X; iY = Y; fStep = 0f; bDown = false; } } } | cs |
새롭게 추가된 구문은 위에나온 코드가 답니다.
6라인의 조건은 이렇습니다.
블럭이 떨어지는것에 대한 허가가 되었나? 그리고
현재 내 위치가 목표 위치와 다른가?
8라인 에서는 시간에 따른 블럭 이동 속도가 초기화 됩니다.
9라인 에서는 현재 내 위치를 변화 시켜줍니다.
MoveTowards() 함수를 이용하여 보간 이동 시켜주는군요.
11라인 에서의 조건은 이렇습니다.
내 위치가 목표위치에 도달했는가?
도달 했다면 목표 위치는 현재 내 위치와 같으므로
16라인에 블럭보드의 특정 위치에 현재 자신의 타입으로 초기화 시켜 줍니다.
17,18라인은 현재 자신의 위치가 목표위치(TartgetPos)와 같으므로 새롭게 정보를 갱신해 줍니다.
19 라인에서는 블럭의 떨어지는 속력을 0으로 초기화 합니다.
그렇지 않으면 다음에 블럭이 또 떨어지는 일이 생길때 너무 속력이 빨라 순간이동 수준으로 보일지도 모르기 때문입니다.
20 라인에서는 현재 내 위치가 목표 위치까지 도달했으므로 더 이상 움직일 필요가 없기 때문에 명령을 철회한다는 것과 같다고 생각 하시면 됩니다.
그럼 다시 GameManager에 BlockDown()함수로 돌아와서
1 2 3 4 | if (bBlockDown) bBlockMoveDown = true; else StartCoroutine(BlockCheck()); | cs |
이 구문은 bBlockDown변수 선언 이유와 함께 설명했으므로 생략 하겠습니다.
다만 bBlockMoveDown변수에 대해서는 설명하고자 합니다.
이 변수는 현재 블럭의 이동이 끝났다면 다음 블럭의 이동을 시작해주기 위한 플래그 변수 입니다.
현재 블럭의 이동이 끝난지 알수 없기 때문에 그에따른 체크를 해야 합니다.
Update() 함수로 이동합시다.
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 | void Update() { if (bBlockMoveDown) { // 블럭이 움직인다: true // 블럭이 움직이지 않는다 : false bool bBlockMoveEnd = false; GameObject[] blocks = GameObject.FindGameObjectsWithTag("BLOCK"); foreach (GameObject block in blocks) { // 움직이는 블럭이 있는지 bDown변수를 체크해여 확인. // 조건 : 움직이는 블럭이 있다면. if (block.GetComponent<Block>().bDown) { // 움직이는 블럭이 아직 있으므로 bBlockMoveEnd을 true로 변환. bBlockMoveEnd = true; break; } } // 블럭이 움직이지 않는다면. if (!bBlockMoveEnd) { bBlockMoveDown = false; BlockDown(); } } } | cs |
현재는 bBlockMoveDown변수가 true되었기 때문에 현재 블럭들이 이동을 하고있는지, 그렇지 않은지 체크가 가능해졌습니다.
모든 블럭의 bDown값을 체크 합니다. 만약 하나라도 true이라면 현재 이동하고 있는 블럭이 존재하는 것이므로,
7라인의 선언된 bool값을 true값으로 변환 시켜 줍니다.
만약 bDown값이 true인것이 하나도 없다면 이동하고 있는 블럭이 존재하지 않는다는 의미 이므로 다음 빈 칸 이동을 위한 BlockDown()함수(27라인)를 호출해 줍니다.
'Unity3D > Project' 카테고리의 다른 글
[Unity3D] 헥사게임 만들기 네 번째 - 마우스 처리2 (0) | 2018.03.14 |
---|---|
[Unity3D] 헥사게임 만들기 네 번째 - 마우스 처리. (2) | 2018.03.09 |
[Unity3D] 헥사게임 만들기 세 번째 - 블럭 처리. (0) | 2018.02.18 |
[Unity3D] 헥사게임 만들기 두 번째- 블럭보드 만들기2 (0) | 2018.02.13 |
[Unity3D] 헥사게임 만들기 두 번째 - 블럭보드 만들기. (0) | 2018.02.13 |