[모바일 퍼즐 게임] 피즈 펑크! Pz Punk! : The Candy Thief


기획/제작 : 김영조

제작 기간 : 3주

제작 툴 : 유니티



유튜브 영상 링크 : https://www.youtube.com/watch?v=YqW_wrVXG44

다운로드 링크 (안드로이드) : https://play.google.com/store/apps/details?id=com.YJ.PZPunk


----------------------------------------------------------------------------------------------------


게임을 만든 방법

1. DFS 알고리즘 (재귀 함수)

화면상의 과일들을 움직여 3개 이상이 되면 미완성 캔디로 만드는 과정이 필요합니다.
그렇다면 이동된 과일의 상하좌우를 탐색하여 3개 이상이면 캔디로, 아니라면 다시 원위치로 돌아가야 합니다.
이동된 과일의 인접한 부분뿐만 아니라 같은 색으로 이어진 모든 과일들의 주변을 탐색해야 하기 때문에
이를 구현하기 위해 두 가지의 선택지를 생각했습니다.

1. BFS 알고리즘    (큐, 넓이 우선 탐색)
2. DFS 알고리즘    (스택, 재귀 함수, 깊이 우선 탐색)

두 가지 중 DFS 알고리즘이 좀 더 직관적으로 구현하기 좋겠다 생각했고
과일의 체크를 담당하는 Checker라는 클래스를 만들어 재귀 함수를 구현했습니다.

아래는 Checker 클래스의 Connect_Check_Recurse() 재귀 함수의 간략한 설명입니다.

1. 매개 변수로 들어온 x와 y는 해당 과일의 배열 내 인덱스 값이기 때문에 배열의 범위를 벗어나면 안 됩니다. (배열이 곧 퍼즐 판의 크기)
2. 이미 이 메서드로 체크가 된 과일인 경우 체크 대상에서 제외합니다. (같은 타입의 과일이 인접해 있다면 무한 호출에 빠지기 때문입니다.)
3. 현재 떨어지고 있는 과일일 경우 바닥에 착지한 시점부터 체크가 진행되어야 합니다.
4. 같은 타입의 과일인지 체크하고, 같은 타입이라면 이 과일을 기준으로 또다시 상하좌우 체크를 떠나게 됩니다.


유저가 선택한 과일이 지정한 방향으로 이동이 완료되면
선택한 과일을 시작으로 Connent_Check_Recurse() 함수가 호출되게 됩니다.



S를 시작으로 재귀 함수의 호출 순서대로 숫자를 표기했습니다.


1. 유저가 선택한 과일 S를 시작으로 상하좌우 순서로 체크를 떠나기 때문에 1번 과일로 가게 됩니다.

2. 1번 과일이 같은 타입이기 때문에 1번 과일을 기준으로 다시 상하좌우 체크를 하게 됩니다.

3. 1번 과일의 상, 좌, 우측에 있는 과일은 같은 타입이 아니고, 밑은 이미 체크된 과일이기 때문에 재귀 함수의 탈출 조건에 걸리게 됩니다.

4. 1번 과일의 재귀 함수가 완전히 종료되고, 최근에 호출되었던 재귀 함수로 돌아가 나머지 작업을 수행하게 됩니다.

5. 14번째 진행과정은 배열의 범위를 초과한 범위이기 때문에 탈출 조건에 걸리게 됩니다.



2. 버킷 릴레이


위 그림의 번호는 배열 내의 x축 인덱스 값을 나타냅니다.

1번 과일과 2번 과일의 위치를 바꾸어 봅니다.

눈으로 보기에는 성공적으로 위치가 바뀌어 보이지만, 메모리상의 위치는 변함이 없습니다.


1) 화면상의 과일들은 유저의 조작에 따라 인접한 과일과 바뀌는 액션이 필요합니다.

--> 이를 구현하기 위해서 선택한 방법은 버킷 릴레이 방식으로 과일들의 오프셋을 계산해 주는 방식입니다.


A) 과일들이 나열되어 있습니다. 이제 1번과 2번 과일의 위치가 바뀌는 과정을 설명하겠습니다.
B) 1번 과일과 2번 과일의 정보를 바꾸어 줍니다. (과일의 타입 또한 교환되기 때문에 타입이 바뀌게 됩니다.)
2) 두 과일의 위치를 체인지 합니다. 

위의 동작은 한 프레임안에 동작하는 것이기 때문에 플레이어의 눈에는 이동하지 않은 것으로 보이게 됩니다.


그 후 여러 프레임에 걸쳐 두 과일의 위치가 원래 자리로 돌아가게 됩니다.

ex)
1번 과일의 position.x - 2번 과일의 position.x = -1 이라면
위 두 과일의 x축 거리는 (절댓 값) 1만 큼 차이 난다는 것을 의미합니다.

따라서 계산된 값을 서서히 0으로 만드는 과정에서 둘의 위치값에 적절한 수를 연산해 준다면
원하는 위치까지 서서히 이동하는 모션을 구현할 수 있습니다.

이 방식을 사용하면 바로 옆의 과일만 스위치 할 수 있는 것이 아니라
멀리 있는 과일과도 위치가 바뀌는 모션을 사용할 수 있습니다.

만약 계산 결과가 (절댓 값) 4만큼 차이가 난다면 1차이가 났을 때보다 더욱 긴 거리를 이동하게 될 것입니다.


2) 캔디로 만들어진 자리는 빈 공간이 되기 때문에 그 자리를 하늘에서 떨어지는 과일로 채우는 액션이 필요합니다.


이 경우에도 버킷 릴레이 방식을 활용하여 과일이 하늘에서 떨어지는 것처럼 구현할 수 있었습니다.


3. 클래스 재활용

DFS 알고리즘으로 연결된 과일이 몇개인지 확인하는 Checker라는 클래스를 만들었습니다.

1) 게임 시작과 동시에 과일의 초기 배치

--> 3개 이상이 되면 과일이 캔디가 되어버리기 때문에 초기 배치에는 3개 이상이 연결되어 있으면 안 됩니다.
--> 난이도를 생각해서 2개씩 뭉쳐있는 것이 좋다고 판단하여 초기 배치에는 같은 과일이 2개씩 붙어있게 만들었습니다.
--> 적절한 난수를 이용한다면 난이도를 유동적으로 바꿀 수 있습니다.


과일의 초기 배치를 담당하는 FruitMaker 클래스에서 Checker 클래스를 활용하여 초기 배치에 성공했습니다.

2) 과일을 인접 과일과 스위치

--> 선택된 과일이 유저가 선택한 방향으로 옮겨졌다면 이동 완료와 동시에 주위 과일들을 탐색하여
캔디로 바꿀 것인지 혹은 원 위치로 다시 돌아갈 것인지 결정해야 합니다.

과일의 이동을 담당하는 FruitCtrl 클래스에서 Checker 클래스를 활용하여 3개 이상이면 변환, 아니라면 다시 스위치 하도록 구현했습니다.

3) 빈 공간을 떨어지는 과일로 채우기

--> 캔디로 바뀐 빈 공간은 다시 다른 과일들로 채워져야 합니다.
--> 하늘에서 과일이 떨어져 빈 공간을 채우는 형식으로 모두 떨어진 뒤에는 인접한 곳에 자신과 같은 과일이 있는지 확인해야 합니다.

이 또한 과일의 이동을 담당하는 FruitCtrl 클래스에서 Checker 클래스를 활용하여 떨어진 과일의 인접 과일을 체크하도록 했습니다.

4) 미완성 캔디가 이어진 수에 따른 Crush

--> 미완성 캔디의 이어진 수가 많을수록 더욱 많은 보너스 점수를 받을 수 있습니다.
--> 때문에 미완성 캔디의 이어진 수를 확인하는 것도 주요 작업 중 하나입니다.


Checker 클래스의 상하좌우로 동일한 객체를 찾는 로직을 이용하여 미완성 캔디의 수를 카운트했습니다.


4. 오브젝트 풀

과일로 만들어진 캔디를 박스에 담는 것이 주요 점수원이기 때문에 캔디를 매번 생성해 주어야 합니다.


1) 게임이 끝날 때까지 많게는 수 천 번의 캔디 생성이 있을 수 있기 때문에 캔디를 게임 시작과 동시에 적정량을 미리 생성했습니다.
2) 생성된 캔디는 캔디 리스트에 저장되어 비활성 상태로 대기하게 됩니다.
3) 캔디가 필요한 위치에 활성 상태로 나타나게 되며, 화면에서 사라진다면 다시 캔디 리스트에 비활성 상태로 대기하게 됩니다.


5. 구글 플레이 게임 서비스


퍼즐 게임의 특성상 점수의 기록이 매우 중요하기 때문에 구글 플레이 게임 서비스와 연동하여 랭킹 시스템을 추가했습니다.
또한 18가지의 업적을 추가하여 게임을 하면서 숨겨진 미션들을 완료할 수 있게 콘텐츠를 추가했습니다.


+ Recent posts