글
[TetrisManager 클래스의 Class Diagram]
테트리스의 전반적인 로직을 담당하는 TetrisManager 클래스에 대해서 살펴보겠습니다. TetrisManager.c 에서 변경된 부분 위주로 설명드리겠습니다. 추가, 삭제, 변경 이력에 대해서 말씀드리겠습니다.
[TetrisManager.c 버전 비교 (1)]
8, 9, 12 라인 (변경)
[TetrisManager.c 버전 비교 (2)]
49 라인 (삭제)
70 라인 (삭제)
[TetrisManager.c 버전 비교 (3)]
149, 151 라인 (추가)
154, 156 라인 (추가)
171, 173 ~ 186 라인 (추가)
이제는, 위에서 언급한 부분들을 분석해 보겠습니다.
[TetrisManager.c]
#include <stdio.h> #include <string.h> #include <windows.h> #include "TetrisManager.h" #include "Util.h" #include "Constant.h" #define INITIAL_SPEED 400 #define SPEED_LEVEL_OFFSET 50 #define LEVELP_UP_CONDITION 3 #define STATUS_POSITION_X_TO_PRINT 40 #define STATUS_POSITION_Y_TO_PRINT 3 static void _TetrisManager_ClearBoard(TetrisManager* tetrisManager); static void _TetrisManager_ChangeBoardByStatus(TetrisManager* tetrisManager, int status); static void _TetrisManager_UpSpeedLevel(TetrisManager* tetrisManager); static void _TetrisManager_SearchLineIndexesToDelete(TetrisManager* tetrisManager, int* indexes, int* count); static void _TetrisManager_DeleteLines(TetrisManager* tetrisManager, int* indexes, int count); void TetrisManager_Init(TetrisManager* tetrisManager, int speedLevel){ Block block; block.current = -1; memset(tetrisManager->board, 0, sizeof(char)* BOARD_ROW_SIZE * BOARD_COL_SIZE); _TetrisManager_ClearBoard(tetrisManager); tetrisManager->block = Block_Make(True, block); tetrisManager->deletedLineCount = 0; tetrisManager->speedLevel = speedLevel; } int TetrisManager_CheckValidPosition(TetrisManager* tetrisManager, int direction){ Block temp = Block_Move(tetrisManager->block, direction); int i; for (i = 0; i < POSITIONS_SIZE; i++){ int x = Block_GetPositions(temp)[i].x; int y = Block_GetPositions(temp)[i].y; if (tetrisManager->board[x][y] != EMPTY && tetrisManager->board[x][y] != MOVING_BLOCK){ return tetrisManager->board[x][y]; } } return EMPTY; } void TetrisManager_ChangeBoardByDirection(TetrisManager* tetrisManager, int direction){ int tempDirection = DOWN; int tempCheckResult = EMPTY; _TetrisManager_ClearBoard(tetrisManager); int checkResult = TetrisManager_CheckValidPosition(tetrisManager, direction); if (checkResult == EMPTY){ tetrisManager->block = Block_Move(tetrisManager->block, direction); } else{ if (direction == UP){ switch (checkResult){ case TOP_WALL: tempDirection = DOWN; tempCheckResult = TOP_WALL; break; case RIGHT_WALL: tempDirection = LEFT; tempCheckResult = RIGHT_WALL; break; case LEFT_WALL: tempDirection = RIGHT; tempCheckResult = LEFT_WALL; break; } do{ tetrisManager->block = Block_Move(tetrisManager->block, tempDirection); } while (TetrisManager_CheckValidPosition(tetrisManager, direction) == tempCheckResult); tetrisManager->block = Block_Move(tetrisManager->block, direction); } } _TetrisManager_ChangeBoardByStatus(tetrisManager, MOVING_BLOCK); } void TetrisManager_ChangeBoardByAuto(TetrisManager* tetrisManager){ TetrisManager_ChangeBoardByDirection(tetrisManager, DOWN); } void TetrisManager_ProcessDirectDown(TetrisManager* tetrisManager){ while (!TetrisManager_IsReachedToBottom(tetrisManager)){ TetrisManager_ChangeBoardByDirection(tetrisManager, DOWN); } } void TetrisManager_ProcessDeletingLines(TetrisManager* tetrisManager){ int indexes[BOARD_ROW_SIZE]; int count; int i; _TetrisManager_SearchLineIndexesToDelete(tetrisManager, indexes, &count); if (count > 0){ _TetrisManager_DeleteLines(tetrisManager, indexes, count); for (i = tetrisManager->speedLevel; i <= tetrisManager->deletedLineCount / LEVELP_UP_CONDITION; i++){ _TetrisManager_UpSpeedLevel(tetrisManager); } } } int TetrisManager_IsReachedToBottom(TetrisManager* tetrisManager){ int i; for (i = 0; i < POSITIONS_SIZE; i++){ int x = Block_GetPositions(tetrisManager->block)[i].x; int y = Block_GetPositions(tetrisManager->block)[i].y; if (tetrisManager->board[x + 1][y] != EMPTY && tetrisManager->board[x + 1][y] != MOVING_BLOCK){ return True; } } return False; } int TetrisManager_ProcessReachedCase(TetrisManager* tetrisManager){ _TetrisManager_ChangeBoardByStatus(tetrisManager, FIXED_BLOCK); tetrisManager->block = Block_Make(False, tetrisManager->block); if (TetrisManager_IsReachedToBottom(tetrisManager)){ return END; } else{ return PLAYING; } } void TetrisManager_Sleep(TetrisManager* tetrisManager){ Sleep(TetrisManager_GetDownMilliSecond(tetrisManager)); } void TetrisManager_Print(TetrisManager* tetrisManager){ int i; int j; CursorUtil_GotoXY(0, 0); for (i = 0; i < BOARD_ROW_SIZE; i++){ for (j = 0; j < BOARD_COL_SIZE; j++){ switch (tetrisManager->board[i][j]){ case LEFT_TOP_EDGE: printf("┎"); break; case RIGHT_TOP_EDGE: printf("┒"); break; case LEFT_BOTTOM_EDGE: printf("┖"); break; case RIGHT_BOTTOM_EDGE: printf("┚"); break; case EMPTY: printf(" "); break; case MOVING_BLOCK: FontUtil_ChangeFontColor(tetrisManager->block.color); printf("■"); FontUtil_ChangeFontColor(WHITE); break; case FIXED_BLOCK: FontUtil_ChangeFontColor(JADE); printf("▧"); FontUtil_ChangeFontColor(WHITE); break; case LEFT_WALL: case RIGHT_WALL: printf("|"); break; case TOP_WALL: case BOTTOM_WALL: printf("―"); break; } } printf("\n"); } CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT); printf("********* Tetris *********\n"); CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 1); printf("[%d level / %d lines deleted]\n", tetrisManager->speedLevel, tetrisManager->deletedLineCount); CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 3); printf("[Key Description]\n"); CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 4); printf("← : move left\n"); CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 5); printf("→ : move right\n"); CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 6); printf("↓ : move down\n"); CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 7); printf("↑ : rotate\n"); CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 8); printf("SpaceBar : direct down\n"); Block_PrintNext(tetrisManager->block, STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 11); CursorUtil_Hide(); } DWORD TetrisManager_GetDownMilliSecond(TetrisManager* tetrisManager){ int i; DWORD milliSecond = INITIAL_SPEED; for (i = MIN_SPEED_LEVEL; i < tetrisManager->speedLevel; i++){ if (i < MAX_SPEED_LEVEL / 2){ milliSecond -= SPEED_LEVEL_OFFSET; } else{ milliSecond -= (SPEED_LEVEL_OFFSET / 5); } } return milliSecond; } static void _TetrisManager_ClearBoard(TetrisManager* tetrisManager){ int i; int j; for (i = 0; i < BOARD_ROW_SIZE; i++){ tetrisManager->board[i][0] = LEFT_WALL; tetrisManager->board[i][BOARD_COL_SIZE - 1] = RIGHT_WALL; } for (i = 0; i < BOARD_COL_SIZE; i++){ tetrisManager->board[0][i] = TOP_WALL; tetrisManager->board[BOARD_ROW_SIZE - 1][i] = BOTTOM_WALL; } for (i = 1; i < BOARD_ROW_SIZE - 1; i++){ for (j = 1; j < BOARD_COL_SIZE - 1; j++){ if (tetrisManager->board[i][j] != FIXED_BLOCK){ tetrisManager->board[i][j] = EMPTY; } } } tetrisManager->board[0][0] = LEFT_TOP_EDGE; tetrisManager->board[0][BOARD_COL_SIZE - 1] = RIGHT_TOP_EDGE; tetrisManager->board[BOARD_ROW_SIZE - 1][0] = LEFT_BOTTOM_EDGE; tetrisManager->board[BOARD_ROW_SIZE - 1][BOARD_COL_SIZE - 1] = RIGHT_BOTTOM_EDGE; } static void _TetrisManager_ChangeBoardByStatus(TetrisManager* tetrisManager, int status){ int i; for (i = 0; i < POSITIONS_SIZE; i++){ int x = Block_GetPositions(tetrisManager->block)[i].x; int y = Block_GetPositions(tetrisManager->block)[i].y; tetrisManager->board[x][y] = status; } } static void _TetrisManager_UpSpeedLevel(TetrisManager* tetrisManager){ if (tetrisManager->speedLevel < MAX_SPEED_LEVEL){ tetrisManager->speedLevel++; } } static void _TetrisManager_SearchLineIndexesToDelete(TetrisManager* tetrisManager, int* indexes, int* count){ int i; int j; int toDelete; memset(indexes, -1, sizeof(int)* (BOARD_ROW_SIZE - 2)); *count = 0; for (i = 1; i < BOARD_ROW_SIZE - 1; i++){ toDelete = True; for (j = 1; j < BOARD_COL_SIZE - 1; j++){ if (tetrisManager->board[i][j] != FIXED_BLOCK){ toDelete = False; break; } } if (toDelete){ indexes[(*count)++] = i; } } } static void _TetrisManager_DeleteLines(TetrisManager* tetrisManager, int* indexes, int count){ int i; int j; int k = BOARD_ROW_SIZE - 2; int toDelete; char temp[BOARD_ROW_SIZE][BOARD_COL_SIZE] = { EMPTY }; for (i = BOARD_ROW_SIZE - 2; i > 0; i--){ toDelete = False; for (j = 0; j < BOARD_COL_SIZE; j++){ if (i == indexes[j]){ toDelete = True; break; } } if (!toDelete){ for (j = 0; j < BOARD_COL_SIZE; j++){ temp[k][j] = tetrisManager->board[i][j]; } k--; } } for (i = 1; i < BOARD_ROW_SIZE - 1; i++){ for (j = 1; j < BOARD_COL_SIZE - 1; j++){ tetrisManager->board[i][j] = temp[i][j]; } } tetrisManager->deletedLineCount += count; }
8, 9, 12 라인 (변경)
INITIAL_SPEED 값을 500 에서 400 으로 내려서, 초기 시작 속도를 조금 빠르게 변경하였고, SPEED_LEVEL_OFFSET 값을 100 에서 50 으로 조정하였습니다. 12 라인에서는 STATUS_POSITION_Y_TO_PRINT 값을 6 에서 3 으로 변경하였습니다. (출력 위치의 Y 값 조정)
49 라인 (삭제)
사용자가 연속으로 UP 키를 누르고 있을 때의 처리였는데, main.c 에서의 소스 코드 변경으로 인해 필요가 없어져서 삭제했습니다.
70 라인 (삭제)
양쪽 벽에 닿았을 때 계속 벽 방향 키를 연속으로 누르고 있을 때의 처리였는데, 마찬가지로 main.c 에서의 소스 코드 변경으로 인해 필요가 없어져서 삭제했습니다.
149, 151 라인 (추가)
이동중인 블럭을 출력하기 위해 149 라인에서 먼저 해당 block 의 color 를 가지고 콘솔 출력 커서의 색상을 변경합니다 (FontUtil_ChangeFontColor 함수를 통해). 그리고 이동중인 블럭을 150 라인에서 출력하고 난뒤에는, 151 라인에서 다시 원래 색상인 흰색으로 출력 커서의 색상을 되돌려 놓습니다. (FontUtil_ChangeFontcolor 함수 호출 통해서)
154, 156 라인 (추가)
고정된 블럭을 출력하기 위해 154 라인에서 먼저 JADE 색상 (비취색) 을 가지고 콘솔 출력 커서의 색상을 변경합니다 (FontUtil_ChangeFontColor 함수를 통해). 그리고 고정 블럭을 155 라인에서 출력하고 난뒤에는, 156 라인에서 다시 원래 색상인 흰색으로 출력 커서의 색상을 되돌려 놓습니다. (FontUtil_ChangeFontcolor 함수 호출 통해서)
171, 173 ~ 186 라인 (추가)
사용자 키 설명 가이드를 화면에 출력합니다. (상, 하, 좌, 우, 스페이스 바)
'1.2) 프로젝트 > 테트리스' 카테고리의 다른 글
테트리스 ver 0.6 (1) - 실행 결과 & 프로젝트 개요 (6) | 2016.02.23 |
---|---|
테트리스 ver 0.5 (1) - 실행 결과 & 프로젝트 개요 (0) | 2016.02.23 |
테트리스 ver 0.4 (1) - 실행 결과 & 프로젝트 개요 (6) | 2015.08.21 |
테트리스 ver 0.3 (9) - 개발 완료 / 후기 (0) | 2015.08.21 |
테트리스 ver 0.3 (8) - 소스코드 구현 (Main) (0) | 2015.08.21 |
테트리스 ver 0.3 (6) - 소스코드 구현 (Block) (0) | 2015.08.21 |
테트리스 ver 0.3 (5) - 소스코드 구현 (Util) (0) | 2015.08.21 |
테트리스 ver 0.3 (4) - 소스코드 변경 내역 (0) | 2015.08.20 |
테트리스 ver 0.3 (3) - 프로그램 설계 (Use Case, Class, Sequence) (0) | 2015.08.20 |
테트리스 ver 0.3 (2) - 요구사항 분석 (0) | 2015.08.20 |
RECENT COMMENT