<테트리스 게임> 프로젝트
- 블록의 소멸과 점수와 레벨 추가
작업 환경 : 윈도우 10, Visual Studio, C++ (Win32 Console)
블록의 소멸 (가득찬 줄의 블록 소멸)
RemoveFillUpLine 함수는 가득찬 줄을 제거하는 함수로, BlockDown함수 내부에서 호출된다. 이 블록소멸 함수 호출전에 반드시 AddCurrentBlockInfoToBoard 함수 호출이 필요하다.
AddCurrentBlockInfoToBoard 함수는, 이전 단계에서는 main함수내에서 블럭을 아래로 내리는데 실패했을 때에 블럭을 굳히기 위해 호출되던 함수였다. 이 함수를 통해 커서 위치 정보를 배열 index 정보로 변경해 굳어진 블록의 정보를 게임판에 추가할 수 있었다.
- BlockDown 함수 내부
1 2 3 4 5 6 7 8 9 10 | BOOL BlockDown(void) { if (!DetectCollision(curPosX, curPosY + 1, blockModel[GetCurrentBlockIdx()])) { /* 행 단위로 채워진 블록 정보 검사*/ AddCurrentBlockInfoToBoard(); RemoveFillUpLine(); return FALSE; } ( . . . .) | cs |
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 | void RemoveFillUpLine(void) { int x, y; int line; for (y = GBOARD_HEIGHT - 1; y>0; y--) // 게임판 배열의 경계를 제외하고 순회 { for (x = 1; x < GBOARD_WIDTH + 1; x++) { if (gameBoard[y][x] == 0) // 채워지지 않은 부분(0)이 있으면 빠져나감 break; } if (x == (GBOARD_WIDTH + 1)) // 한줄이 다 채워졌다면 { for (line = 0; y - line>0; line++) { memmove( &gameBoard[y - line][1], &gameBoard[(y - line) - 1][1], GBOARD_WIDTH * sizeof(int) ); } y++; // 배열 정보가 아래로 한 칸씩 이동했으므로 } } DrawSolidBlocks(); } | cs |
먼저 게임판의 경계를 제외한 모든 배열을 for문을 통해 순회하며 검사하고, 한줄이 블럭으로 다 채워져있는지(1)를 비교연산한다.
1이 아닌 값이 있다는 건 한줄이 다 채워지지 않았음을 의미한다.
1 2 | void *memmove(void *dest, const void*src, size_t n); // dest: 복사대상 메모리, src:복사원 메모리, n: 복사할 길이 | cs |
[ 첫번째 가득찬 줄의 삭제 과정 ]
[ 두번째 가득찬 줄의 삭제 과정 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void DrawSolidBlocks(void) { int x, y; int cursX, cursY; for (y = 0; y<GBOARD_HEIGHT; y++) { for (x = 1; x<GBOARD_WIDTH + 1; x++) { cursX = x * 2 + GBOARD_ORIGIN_X; cursY = y + GBOARD_ORIGIN_Y; SetCurrentCursorPos(cursX, cursY); if (gameBoard[y][x] == 1) { cout<<"■"; } else { cout << " "; } } } } | cs |
1 2 3 4 5 6 7 8 9 10 11 | void BlockMoveDown(void) // 아래 방향키 입력을 통한 soft drop (space bar입력은 hard drop) { if (!DetectCollision(curPosX, curPosY + 1, blockModel[GetCurrentBlockIdx()])) return; DeleteBlock(blockModel[GetCurrentBlockIdx()]); curPosY += 1; SetCurrentCursorPos(curPosX, curPosY); ShowBlock(blockModel[GetCurrentBlockIdx()]); } | cs |
1 | enum key { LEFT = 75, RIGHT = 77, UP = 72, SPACE = 32, DOWN = 80 }; // up=회전, down= soft drop, space=hard drop | cs |
1 2 3 | case DOWN: BlockMoveDown(); break; | cs |
1 2 3 4 5 | #define LEVER_UP_SCORE 2000 // 게임 레벨을 올리기위한 필요 점수 #define GameSpeed 2 // 값이 클수록 속도가 많이 증가 static int GameLevel = 1; // 레벨 1로 시작 static int GameScore = 0; // 점수 0으로 시작 | cs |
이와 같이 매크로 상수와 변수를 선언한다.
GameLevelUp 함수는 게임 레벨을 올리기위한 함수이다.
1 2 3 4 5 6 7 8 | void GameLevelUp(void) { if (GameLevel > 9) // 레벨 10으로 제한 GameLevel = 9; GameLevel++; increaseGameSpeed(GameSpeed); } | cs |
3-4행 : 게임 레벨을 10으로 제한하기 위한 코드
6행 : 게임레벨의 증가
7행에서 호출하는 increaseGameSpeed 함수는 다음과 같다.
increaseGameSpeed 함수는 게임의 속도를 증가시키기 위한 함수이다.
1 2 3 4 | void increaseGameSpeed(int addSpeed) { keyDelayRate += addSpeed; } | cs |
인자로 전달된 값이 KeyDelayRate값에 변화를 주며, 이 값이 커질수록 게임속도가 빨라지게 된다.
다음은 게임 점수를 추가하는 AddGameScore이다. 인자로 전달된 값이 점수에 추가된다.
점수의 증가외에도 위에서 define한 LEVER_UP_SCORE값을 만족하면 레벨이 상승한다.
이 함수는 블럭이 채워졌을 때 호출되어야 하므로 RemoveFillUpLine 함수내부에서 호출된다.
1 2 3 4 5 6 7 8 | void AddGameScore(int score) // 게임 점수 추가 { GameScore += score; /* 레벨 상승 확인 */ if (GameScore >= GameLevel*LEVER_UP_SCORE) GameLevelUp(); } | cs |
1 2 3 4 5 6 7 8 | void ShowCurrentScoreAndLevel(void) // 점수와 레벨 정보 출력 { SetCurrentCursorPos(30, 4); printf("§ 현재 레벨: %d §", GameLevel); SetCurrentCursorPos(30, 7); printf("§ 현재 점수: %d §", GameScore); } | cs |
RemoveFillUpLine함수에서 AddGameScore와 ShowCurrentScoreAndLevel함수를 호출하는 것을 볼 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void RemoveFillUpLine(void) { int x, y; int line; for (y = GBOARD_HEIGHT - 1; y>0; y--) // 바닥행부터 배열 순회 { ( 생략 . . . .) y++; // 배열 정보가 아래로 한 칸씩 이동했으므로 AddGameScore(1000); ShowCurrentScoreAndLevel(); } } DrawSolidBlocks(); } | cs |
다음은 수정된 KeyInput 함수이다.
KeyDelayRate는 특정값으로 값을 초기화해 게임 시작시의 속도를 결정한다. 또한 increaseGameSpeed함수에 의해 레벨이 증가할수록 값이 작아지게 되어, 블럭이 빨리 내려오게 된다.
20-21행에서는 속도가 너무 빨라지지 않도록 KeyDelayRate값을 고정하고 있다.
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 | static int keyDelayRate; // 값이 클수록 속도 증가 int KeyInput(void) // space bar입력시 1 반환, main함수에서 조건만족시 새로운 블록 생성 { int key; for (int i = 0; i < KEY_SENSITIVE; i++) // #define KEY_SENSITIVE 100 (키 입력감도) { if (_kbhit() != 0) { key = _getch(); switch (key) { case LEFT: BlockMoveLeft(); break; ( 생략 . . . .) } } if (keyDelayRate < 30) // 특정 속도 이상 증가하지않도록 고정 keyDelayRate = 30; Sleep(delay); } return 0; } | cs |
추가할 기능
: 블럭 소멸시 애니메이션, 사운드, next block, 게임 정지, ↓입력시 빠른 하강, 아이템
한꺼번에 많은 줄을 없앨수록 높은 점수 증가, 경과 시간 표시
'코스웨어 > 16년 스마트컨트롤러' 카테고리의 다른 글
2016-11-03_조재찬_스터디일지_단순 연결리스트에 파일 입출력 응용 / C복습 (0) | 2016.11.03 |
---|---|
아두이노 부트로더 복구 (0) | 2016.10.27 |
2016.03.02 구조체와 응용 (0) | 2016.10.19 |
2016-10-13_조재찬_스터디일지_CPP-상속의 이해 (0) | 2016.10.13 |
2016-10-07_조재찬_ 프로젝트 일지_테트리스 게임 (3) (0) | 2016.10.07 |
2016-10-05_조재찬_ 프로젝트 일지_테트리스 게임 (2) (0) | 2016.10.05 |
2016-10-04_조재찬_ 프로젝트 일지_테트리스 게임 (0) | 2016.10.04 |
2016-09-29_조재찬_스터디일지_CPP-'상속'의 기본 개념, 핸들러 클래스 (0) | 2016.09.30 |