앞서, 프로그램의 실행화면과 설계 / 개발 환경 및 사용된 Tool 들을 정의했고, 요구사항 분석을 했으니, 이제는 StarUML 을 사용하여 진행한 설계 부분 내용을 말씀드릴 차례입니다.


[TetrisForDesktop 의 Use Case Diagram]


사용자와 Tetris 앱 간의 상호작용을 그림으로 나타내어 보면, 위와 같은 Use Case Diagram 을 만들 수 있습니다. Tetris App 이 갖고 있는 여러 기능들 중에서, 직접적으로 사용자에게 제공되는 기능들은 블럭 이동시키기, 블럭 회전시키기, 블럭 및 테트리스 판 출력하기 입니다. Tetris 앱 입장에서는 블럭 이동시키기와 블럭 회전시키기 기능들이 새 블럭을 생성한 후에야 비로소 진행되기 때문에, include 로 표현하였습니다. 또한, 출력하는 부분도, 블럭이 이동되거나, 회전이 된 후에야 가능하기 때문에, 이도 마찬가지로 include 로 표현을 하였습니다. 결론적으로, Tetris 앱은 새 블럭을 생성하면서, 반복적으로 사용자의 요구를 받아서 (키 입력을 통해), 생성된 블럭을 이동시키거나, 회전시킨 후에, 결과 (블럭 및 테트리스 판) 를 출력하게 되는 것입니다.


[TetrisForDesktop 의 Class Diagram]


Use Case Diagram 을 통해서, 거시적 설계를 완료하였으니, 미시적 설계를 위해 Class Diagram 을 작성하였습니다. 크게, Tetris 로직을 담당하는 TetrisView - TetrisManager - Block - Point 클래스가 있고, 여기저기서 사용할 수 있는 Util 클래스, 그 외에 Enum 상수 클래스들이 있습니다.


[Util 의 함수들]

 함수명

매개변수

(변수명 : 자료형)

반환형

설명

CursorUtil_GotoXY

x : int

y : int

Block

커서의 위치를

x, y 위치로 이동합니다.

CursorUtil_Hide


Block

커서를 노출하지

않게 합니다.


Util 클래스는 테트리스 프로그램 전반에서 사용되는 Util 성 함수들을 모아놓은 클래스입니다. 정확히는, TetrisManager 와 Block 클래스에서 사용합니다. 먼저, CursorUtil_GotoXY 함수는 특정 x, y 좌표로 커서의 위치를 이동시키는 역할을 합니다. CursorUtil_Hide 함수는 커서를 보이지 않게 숨기는 역할을 합니다.


[Point 의 변수들]

 변수명

자료형

설명 

x

int

위치의 x 좌표 

y

int

위치의 y 좌표 


Point 클래스는 테트리스 판에서 한 지점을 나타냅니다. 그 지점의 x, y 좌표를 담고 있고, 이를 통해, 테트리스 블럭 상자 각각의 위치를 쉽게 표현할 수 있습니다.


[Block 의 변수들]

 변수명

자료형

설명 

positions

Point [4][4]

1 개의 블럭을 

(4 개 상자)

0 도, 90 도, 

180 도, 270 도

회전한 모든 좌표

current

int

미리 정의한

총 6 가지의

다른 형태의

블럭들 중

현재 내려오는

블럭의 인덱스

next

int

현재 블럭 말고

다음 블럭을

가리키는 인덱스 

direction

int

블럭의 방향

(위, 아래, 좌, 우)


Block 클래스는 생성되는 블럭을 나타냅니다. 하나의 블럭은 총 4 개의 상자로 이루어져 있습니다.


[블럭의 종류 6 가지 형태]


블럭의 종류는 위 그림과 같이 총 6 개입니다. 하나의 블럭은 네모 상자 4 개가 붙여져 이루어지기 때문에, 각각 네모 상자 하나마다, x, y 좌표를 가지게 됩니다. 따라서, 블럭 1 개는, 4 개의 좌표를 관리해야 합니다. 이것을 positions 라는 2 차원 배열로 관리합니다. 하나의 블럭당 4 개의 좌표가 필요하고, 또, 0 도, 90 도, 180 도, 270 도로 회전한 모습의 블럭의 좌표도 각각 기억해야 하기 때문에, 4 X 4 인 2 차원 배열을 이용하였습니다. current 변수는 현재 화면에서 내려오고 있는 블럭의 인덱스 (0 부터 시작) 을 저장합니다. 만약, 블럭 4 가 현재 화면에서 보여지고 있다면, current 에는, 4 - 1 인 3 이 저장되어 있을 것입니다. 그리고, next 는 현재 블럭을 만들면서, 동시에 다음 내려올 블럭도 생성을 하는데, 다음 내려올 블럭의 인덱스를 담게 됩니다. 마지막으로, direction 은 현재 블럭이 어느 방향으로 회전되어 화면에 출력되는지 방향을 저장하는 변수입니다. 방향은 상, 하, 좌, 우 이렇게 4 가지로 이루어져 있습니다.


[블럭이 90 도씩 회전 하는 경우 모양]


위와 같은 블럭이 생성되었다고 가정 했을 경우에, 먼저 direction 은 UP (= 0) 이 저장되게 됩니다. 그다음에, 사용자가 회전을 요구하면, 한 번 회전을 하기 때문에 direction 은 RIGHT (= 1) 가 저장됩니다. 이런 식으로 한 번씩 회전할 때마다 90 도씩 회전한 모습의 블럭의 인덱스 (방향) 를 direction 변수로 관리하는 것입니다.


[Block 의 함수들]

 함수명

매개변수

(변수명 : 자료형)

반환형

설명

Block_Make

isFirst : int

block : Block

Block

새 블럭을 

생성합니다.

Block_Move

block : Block

direction : int

Block

블럭을

이동시키거나 

회전시킵니다.

Block_GetPositions

 block : Block

Point*

블럭에서

현재 방향으로

놓여 있는

4 개 상자의

좌표들을

반환합니다.

Block_PrintNext

block : Block

x : int

y : int


다음 블럭을

정해진 위치에

(x, y)

출력합니다.


Block_Make 함수는 6 개 종류의 블럭들 중에서 하나를 랜덤하게 골라서 생성해주는 함수입니다. Block_Move 함수는 블럭을 좌, 우, 아래로 이동시키거나, 회전시키는 함수입니다. Block_GetPositions 함수는 블럭에서 현재 방향으로 놓여져 있는 4 개의 상자들의 위치 좌표들을 반환합니다. 마지막으로, Block_PrintNext 함수는 다음 블럭을 정해진 위치 (x, y) 에 출력하는 역할을 합니다.


[TetrisManager 의 변수들]

 변수명

자료형

설명

board

char [20][14]

테트리스 판

block

Block

블럭 정보 

(현재, 다음)

deletedLineCount

int

한 줄을 모두 상자로

채워 지워진 줄 수

speedLevel

int

블럭이 떨어지는

속도 레벨


TetrisManager 클래스는 테트리스의 전반적인 로직을 담당하는 클래스입니다. board 변수는 테트리스 판을 나타냅니다. 2 차원 배열로 이루어져 있고, 가로 14 줄 X 세로 20 줄의 크기로 구성되어 있습니다.


[테트리스 판의 크기]


가장 가장자리 1 줄은 벽이고, 나머지, 18 줄 X 12 줄이 실제로 테트리스 블럭이 움직일 수 있는 아무것도 없는 빈 공간이 됩니다. 변수 block 은 현재 움직이는 블럭 정보와, 다음에 생성될 블럭 정보 모두 가지고 있습니다. deletedLineCount 는 블럭이 내려올 수 있을 때까지 내려와서 (바로 아래가 아래 벽이거나, 고정되어 굳어진 블럭인 경우) 굳어져서, 이 굳어진 블럭들이 한 줄을 만들게 되면, 그 줄은 삭제가 됩니다. 그 때 삭제되는 줄 수를 기억하는 변수가 deletedLineCount 입니다. 마지막으로, speedLevel 은 블럭이 내려오는 속도를 결정하는 변수입니다. 이는, 맨 처음에 게임 시작시에, 사용자에게 입력을 받습니다. (1 ~ 10 사이의 정수) 1 이 가장 느린 속도이고, 10 은 가장 빠른 속도입니다. 이는, 앞서, deletedLineCount 가 3 씩 증가할때마다 speedLevel 도 자동으로 1 씩 증가하게 됩니다.


[TetrisManager 의 함수들]

 함수명

매개변수

(변수명 : 자료형)

반환형

설명

TetrisManager_Init

tetrisManager : TetrisManager*


speedLevel : int


테트리스 판을 

생성하고, 

각종 변수들 

초기화합니다.

TetrisManager_CheckValidPosition

tetrisManager : TetrisManager*


direction : int

int

해당 방향으로

이동하거나

회전이 가능한지를

판단하여

반환합니다.

TetrisManager_ChangeBoardByDirection

 tetrisManager : TetrisManager*


direction : int


상하좌우

방향을 입력받아

블럭을 처리합니다.

TetrisManager_ChangeBoardByAuto

tetrisManager : TetrisManager*


입력이 없을 시

속도 레벨에 따라

자동으로 블럭을

한 칸 내려줍니다.

TetrisManager_ProcessDirectDown

tetrisManager : TetrisManager*


스페이스바를

눌렀을 시

현재 블럭을

가장 밑으로 

내려줍니다.

TetrisManager_ProcessDeletingLines

tetrisManager : TetrisManager*


테트리스 판에서

삭제될 라인을 찾아

모두 삭제합니다.

TetrisManager_IsReachedToBottom

tetrisManager : TetrisManager*

int

블럭이 밑으로

더 이상 내려갈 수

있는지 판단합니다.

TetrisManager_ProcessReachedCase

tetrisManager : TetrisManager*

int

블럭이 밑으로

더 이상 내려가지

못하는 경우를

처리합니다.

TetrisManager_Sleep

tetrisManager : TetrisManager*


속도 레벨에 따라

블럭이 내려오는 것을

지연시킵니다.

TetrisManager_Print

tetrisManager : TetrisManager*


테트리스 판과

블럭을 화면에

출력합니다.


TetrisManager_Init 함수는 TetrisManager 의 모든 변수들을 생성하고 초기화합니다. 테트리스 판을 만들고, 가장자리에 벽을 세우고, 가운데는 빈 공간으로 채웁니다.


[테트리스 판의 구성 요소]


판을 만들고, 벽을 상하좌우로 채웁니다. (LW -> LEFT WALL, RW -> RIGHT WALL, TW -> TOP WALL, BW -> BOTTOM WALL) 그리고, 4 곳의 모서리를 채웁니다. (LTE -> LEFT TOP EDGE, LBE -> LEFT BOTTOM EDGE, RTE -> RIGHT TOP EDGE, RBE -> RIGHT BOTTOM EDGE) 그리고 안쪽에 빈 공간으로 채웁니다. (E -> EMPTY) 그리고, 새 블럭을 생성합니다. TetrisManager_CheckValidPosition 함수는 다음 진행 방향으로 현재 블럭을 임시로 이동시켜보고 (혹은 회전) 이동 시킨 좌표의 상태가 벽 혹은 모서리, 굳어진 블럭이면 진행할 수 없는 것이고, 그 경우가 아니면 진행해도 되는 것입니다. 이 체크 결과를 반환합니다. (True or False)


[TetrisView 의 변수들]

 변수명

자료형

설명

tetrisManager

TetrisManager 

테트리스의 

실제적인 기능담당 


TetrisView 클래스는 main 함수와 테트리스 logic 간의 중간에서 interface 역할을 하는 역할을 합니다. 즉, 테트리스 프로그램의 껍데기라고 보면 됩니다. main 함수와 같은 테트리스 외부에서 테트리스의 기능을 사용하고자 할때는, 무조건 TetrisView 클래스를 거쳐 가야 합니다. 이런 설계를 통해서, 얻는 장점은, 향후, MVC 패턴으로의 변환이 용이하고, 정보 은닉을 위배하지 않으며, 모듈화가 잘 되고, API 관리가 쉬워지는 등의 많은 이점들이 있습니다. 이 TetrisView 클래스는 멤버 변수로 tetrisManager 를 가지고 있습니다. tetrisManager 는 실제 테트리스 관련 로직을 행하는 클래스 입니다. 따라서, tetrisView 는 실제로 tetris 관련 로직을 처리하지 않고, tetrisManager 에게 위임함으로써, 역할을 철저히 분리하고 있습니다. 실제로, tetrisManager 의 여러 함수들을 합쳐서, tetrisView 에서는 하나의 큰 처리 흐름을 만들게 되는 것입니다.  


[TetrisView 의 함수들]

 함수명

매개변수

(변수명 : 자료형)

반환형

설명

TetrisView_StartGame

tetrisView : TetrisView*

 

게임 시작에 

필요한 작업

TetrisView_ProcessGae

tetrisView : TetrisView*

processType : int

direction : int

 

입력된 키를 통해

게임 진행

TetrisView_EndGame

tetrisView : TetrisView*

 

게임 종료


TetrisView_StartGame 함수는 게임 시작에 필요한 선처리 작업들을 해주는 함수입니다. 테트리스 게임 배경음악을 재생시킨다거나, speed level 을 사용자로부터 입력받아서, 블럭이 내려오는 속도 조절을 하고, TetrisManager 의 멤버 변수들을 초기화 해줍니다. 또, 블럭을 하나 만들어서, 화면에 출력해 주는 역할을 합니다. TetrisView_ProcessGame 함수는 실제로 게임을 진행하는 함수입니다. 사용자로부터 상, 하, 좌, 우, 스페이스 바 등의 키를 입력 받거나, 설정되어 있는 속도 레벨에 따라서, 블럭을 이동시키거나, 회전하고, 그것을 화면에 갱신하는 처리를 합니다. 마지막으로, TetrisView_EndGame 함수는 블럭이 테트리스 판의 가장 윗 부분까지 쌓였을 경우에 게임을 종료하는 역할을 담당하고 있습니다.


Use Case Diagram 과 Class Diagram 으로 프로그램의 기능 및 구조적 설계를 확인했으니, 이제 Sequence Diagram 으로 프로그램의 전반적인 flow 를 설명드릴 차례입니다.


[TetrisForDesktop 의 Sequence Diagram (main 함수)]


위의 Sequence Diagram 은 main 함수의 flow 를 나타낸 것입니다. 편의상 4 depth 까지만 그렸습니다. 먼저, 사용자가 앱을 실행하여 main 함수를 호출합니다. main 함수에서는 TetrisView 의 함수인 TetrisView_StartGame 을 호출합니다. 여기서는, TetrisManager 의 함수들인 TetrisManager_Init 과 TetrisManager_Print 를 호출하면서 게임의 전반적인 세팅 및 초기 상태 출력을 시작하게 됩니다. 세팅이 완료되었으면 loop 를 돌면서, 사용자의 키 입력이 들어오거나 (상, 하, 좌, 우, 스페이스바) 혹은 키 입력이 안들어와도 자동으로 블럭이 내려가야 하는 경우에 이 정보 값을 넘기면서 TetrisView 의 함수인 TetrisView_ProcessGame 함수를 호출합니다. 먼저, 방향 키를 누른 경우 처리를 위해서 (processType 이 DIRECTION 인 경우) TetrisManager 의 TetrisManager_ChangeBoardByDirection 함수를 호출합니다. 두번째로는, 스페이스바를 누른 경우 (processType 이 DIRECT_DOWN 인 경우) 처리를 하기 위해서 TetrisManager 의 TetrisManager_ProcessDirectDown 함수를 호출합니다. 세 번째로, 키 입력이 아닌, speed level 에 따른 자동으로 내려오는 경우 (processType 이 AUTO 인 경우) 처리를 하기 위해서 TetrisManager 의 TetrisManager_ChangeBoardByAuto 함수를 호출합니다. 이렇게 블럭의 움직임을 처리했다면, 그 다음에는, 블럭이 굳어져야 하는 경우를 처리하기 위해서 TetrisManger 의 TetrisManager_IsReachedToBottom 함수를 호출하여 체크하고, 블럭을 굳어지게 합니다. 이 내부에서, 프로그램 종료를 해야하는 경우에는 TetrisView 의 TetrisView_EndGame 을 호출하여 프로그램을 종료합니다. 그 다음에는, 굳어진 블럭들이 한 줄을 채운 경우에, 그 해당 줄을 삭제하기 위해서 TetrisManager 의 TetrisManager_ProcessDeleteLines 를 호출합니다. 그 다음 한번더, 화면 출력을 위해서 TetrisManager_Print 를 호출합니다. 마지막으로, speed level 에 따라서 자동으로 블럭이 내려온 경우에는 TetrisManager_Sleep 함수를 호출하여 일정 시간 동안 딜레이를 줍니다.


[TetrisView_ProcessGame 함수의 흐름 요약]

위의 flow 는 TetrisView_ProcessGame 함수의 흐름을 요약한 것입니다. 먼저, 블록 이동 처리를 하고 그 후에 굳어짐 처리를 하고, 라인 삭제 처리와 딜레이 처리를 순서대로 하는 것으로 요약할 수 있습니다.

by kkikkodev 2015. 6. 12. 11:22