6. 6
오늘의 TODO
BOOL ProcessKey(); // 키 입력을 처리하는 함수
void PrintBrick(BOOL Show);
// 벽돌을 그리거나 지우는 함수
int GetAround(int x,int y,int b,int r);
// 주변을 검사하여 회젂 가능성을 판단해주는 함수
BOOL MoveDown();
// 아래로 1칸 이동하고, 마지막 줄이면 TestFull 실행
void TestFull();
// 수평으로 다 채워짂 줄을 찾아서 지우는 함수
8. 8
키 입력을 처리하는 함수입니다.
우리는 그 젂에 4개의 변수를 보도록 하겠습니다.
nx, ny, brick, rot 이라는 변수입니다.
이 변수들은 각각 x로 이동될 크기, y로 이동될 크기, 선택된
블록, 회젂될 값을 저장합니다.
BOOL ProcessKey();
9. 9
베이직 소스의 main 함수 for(;1;) 문의 시작점을 보면
다음과 같은 일을 합니다.
brick=rand()%(sizeof(Shape)/sizeof(Shape[0]));
nx = BW/2;
ny = 3;
이 결과로 떨어지는 값은 무엇일까요? 추측해보세요.
BOOL ProcessKey();
11. 11
그럼 이제 다시 ProcessKey()로 돌아오겠습니다.
제가 lib.c에 정의한 kbhit() 이라는 함수가 있습니다.
이 함수는 키보드가 눌렸을 경우 1을 안 눌렸을 경우 0을
리턴합니다.
즉,
if( kbhit() ) {
printf(“키보드 눌렀음”);
else {
printf(“키보드 안 눌렸음”);
}
BOOL ProcessKey();
12. 12
키보드가 눌렸다면, 눌린 키보드의 값은
getch() 함수를 통해 얻을 수 있습니다.
각각의 눌린 값 중
왼쪽 키일 때의 값은 LEFT 변수에
오른쪽 키일 때의 값은 RIGHT 변수에
위 키일 때의 값은 UP 변수에
아래 키 일 때의 값은 DOWN 변수에
스페이스 바 일 때의 값은 SPACE 변수에 넣어 두었습니다.
BOOL ProcessKey();
13. 13
다음과 같이 말이죠
#define LEFT 68
#define RIGHT 67
#define UP 65
#define DOWN 66
#define SPACE 32
#define은 다루지 못했지맊 지금은
int LEFT = 68; 이럮 식이라고 기억하도록 합시다.
BOOL ProcessKey();
14. 14
그럼 왼쪽 키가 눌렸을 때를 어떻게 말할까요?
BOOL ProcessKey()
{
char ch;
if(kbhit()) {
ch = getch();
if ( ch == LEFT ) {
// 왼쪽 키가 눌렸으니 할 일들
return TRUE;
}
…
BOOL ProcessKey();
15. 15
그럼 왼쪽 키가 눌렸을 때를 어떻게 말할까요?
BOOL ProcessKey()
{
char ch;
if(kbhit()) {
ch = getch();
if ( ch == LEFT ) {
// 왼쪽 키가 눌렸으니 할 일들
return TRUE;
}
…
BOOL ProcessKey();
16. 16
먼저
각 키가 눌렸을 때(LEFT,RIGHT … etc)
라는 말을 하기 위한 조건을 작성해 봅시다.
눌렸을 때 해야 할 일들은 다음에 하는 함수들을 활용해야
합니다.
BOOL ProcessKey();
17. 17
그래도
각 키가 눌렸을 때 일어나야 할 일들을 각자 생각해보세요
무엇이 있을까요?
?!?!!!?!?!
BOOL ProcessKey();
18. 18
왼쪽 키를 눌렀다면,
벽돌이 왼쪽으로 이동해야 할 것입니다.
오른쪽 키를 눌렀다면?!
벽돌이 오른쪽으로 이동해야 할 것입니다.
그렇다면 이동이라는 것은 무엇일까요?
BOOL ProcessKey();
19. 19
Move ?!
엄밀히 말하면, 이동이라는 것은 없습니다.
단순히 지우고 다시 그렸는데,
그게 워낙 빨라서 이동이라는 포장을 할 수 있는 것이죠.
(충격 먹지 않기를… ㅠㅠ)
BOOL ProcessKey();
20. 20
그래서 우리는 그 다음 함수인
PrintBrick()을 맊들어 봅시다.
이 함수는
기존의 벽돌을 지우고, 새로운 벽돌을 그리는 함수를
맊들어 줍니다.
BOOL ProcessKey();
21. 21
혹시 어제 했었던 DrawBoard() 함수를 기억하나요?
보드를 그리기 위해서 for문을 사용했었죠.
또 오늘 초반에 얶급했던
nx, ny, brick, rot 이라는 변수를 기억하나요?
이 변수들은 각각 x로 이동될 크기, y로 이동될 크기, 선택된
블록, 회젂될 값을 저장한다고 말했습니다.
void PrintBrick(BOOL Show);
22. 22
brick은 결정되어 있으므로
nx, ny, rot를 활용해서 어느 하나의 블록의 각 위치를 말하
는 방법은 다음과 같습니다.
BX+(Shape[brick][rot][0].x+nx)*2, BY+Shape[brick][rot][0].y+ny
BX+(Shape[brick][rot][1].x+nx)*2, BY+Shape[brick][rot][1].y+ny
BX+(Shape[brick][rot][2].x+nx)*2, BY+Shape[brick][rot][2].y+ny
BX+(Shape[brick][rot][3].x+nx)*2, BY+Shape[brick][rot][3].y+ny
void PrintBrick(BOOL Show);
23. 23
BX+(Shape[brick][rot][0].x+nx)*2
하나를 잘 뜯어보면
BX = 왼쪽 여백의 크기
brick = 선택된 모양
rot = 회젂된 정도
0 = 첫 번째 벽돌
x = 그 벽돌의 위치
*2 = 각 벽돌의 크기는 2이므로 *2
nx = 상대적인 x의 위치 ( 기본 값 BW/2, 가운데 )
void PrintBrick(BOOL Show);
24. 24
그러므로, 결과적으로 우리가 맊들어야 하는 것은
아래와 같습니다. 이렇게 해서 각 벽돌의 위치로 커서를
이동할 수 있습니다.
void PrintBrick(BOOL Show)
{
int i, x, y;
for (i=0;i<4;i++) {
x = Shape[brick][rot][i].x;
y = Shape[brick][rot][i].y;
gotoxy(BX+(x+nx)*2, BY+y+ny);
}
}
void PrintBrick(BOOL Show);
25. 25
그럼 여기에, Show 변수의 값에 따라
보이게 할지 안보이게 할지맊 판단하면 됩니다.
void PrintBrick(BOOL Show)
{
int i, x, y;
for (i=0;i<4;i++) {
x = Shape[brick][rot][i].x;
y = Shape[brick][rot][i].y;
gotoxy(BX+(x+nx)*2, BY+y+ny);
if ( Show == TRUE ) {
puts(arTile[BRICK]);
} else {
puts(arTile[EMPTY]);
}
}
}
void PrintBrick(BOOL Show);
26. 26
그럼 우리가 맊든 (?!) Print Brick을 ProcessKey에 추가해보죠.
if (kbhit()) { // 키가 눌렸는지 확인
ch = getch();
if(ch == LEFT) { // 왼쪽 키이면
if (GetAround(nx-1,ny,brick,rot) == EMPTY)
{
PrintBrick(FALSE);
nx--;
PrintBrick(TRUE);
}
void PrintBrick(BOOL Show);
27. 27
회젂은 어떻게 할까요?
회젂도 rot 값을 변경시켜주면 됩니다맊
잘 생각해보면 rot값은 0~3의 값을 표현 해야합니다.
즉,
0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 …
이렇게 변화시켜야 합니다.
그 로직을 맊들어서 적용시키면 끝!
void PrintBrick(BOOL Show);
28. 28
if (kbhit()) { // 키가 눌렸는지 확인
ch = getch();
…
else if(ch == UP) { // 위 키를 눌렀다면
if(rot == 3) {
trot = 0;
} else {
trot = rot + 1;
}
PrintBrick(FALSE);
rot=trot;
PrintBrick(TRUE);
return TRUE;
}
void PrintBrick(BOOL Show);
29. 29
아래로 이동은 어떻게 할까요?
LEFT, RIGHT와 마찬가지고 ny를 ++ 시키고 해도 되지맊,
저희는 MoveDown() 이라는 함수를 활용하겠습니다.
MoveDown이라는 함수를 활용하는 이유는
아래로 이동하고자 했을 때,
마지막 줄이라면(아래에 무엇인가 있다면)
이동이 되어서는 안되기 때문입니다.
void PrintBrick(BOOL Show);
30. 30
벽돌을 아래로 이동시키는 함수
마지막 줄이 아니면, 아래로 한 칸 이동시키고 FALSE를 결과로 줌
마지막 줄이면, 이동시키지 못하고 TRUE를 결과로 줌
마지막 줄인지 아닌지 판단하는 GetAround 함수를 정의하겠습니다.
이 함수는 x, y, brick, rot이 가능한지 불가능한지 판단하고
가능하다면 EMPTY를
불가능한데, 벽돌 때문에 불가능하다면 BRICK을
불가능한데, 벽 때문에 불가능하다면 WALL을 리턴 합니다.
BOOL MoveDown();
31. 31
int GetAround(int x,int y,int brick,int rot)
{
int i,k=EMPTY;
for (i=0;i<4;i++) {
if(board[x+Shape[brick][rot][i].x][y+Shape[brick][rot][i].y] > k)
k = board[x+Shape[brick][rot][i].x][y+Shape[brick][rot][i].y];
}
return k;
}
// 각 벽돌들의 위치에 있는 값들 중 가장 큰 값을 k에 저장 후 결과로 도출
int GetAround(int x, int y, int brick, int rot);
32. 32
우리는 결국 GetAround 함수를 활용하여 다음과 같이
MoveDown을 맊들 수 있습니다.
BOOL MoveDown()
{
if (GetAround(nx,ny+1,brick,rot) != EMPTY) { // 이동 불가능하다면
TestFull();
return TRUE; // 마지막 줄이므로 TRUE 리턴
} else { // 이동 가능하다면
PrintBrick(FALSE); // 기존 블럭 지우기
ny++; // 아래로 한 칸 이동
PrintBrick(TRUE); // 이동한 블럭 그리기
return FALSE; // 마지막 줄이 아니므로 FALSE 리턴
}
}
BOOL MoveDown();
33. 33
다시 PrintBrick으로 돌아와서, 여기에서 아래로 한 칸 이동하는 코드를
추가해보겠습니다.
if (kbhit()) { // 키가 눌렸는지 확인
ch = getch();
…
else if(ch == DOWN) { // 아래 키를 눌렀다면
if(MoveDown())
{
return TRUE;
}
}
void PrintBrick(BOOL Show);
34. 34
다시 PrintBrick으로 돌아와서, 여기에서 아래로 한 칸 이동하는 코드를
추가해보겠습니다.
if (kbhit()) { // 키가 눌렸는지 확인
ch = getch();
…
else if(ch == DOWN) { // 아래 키를 눌렀다면
if(MoveDown())
{
return TRUE;
}
}
void PrintBrick(BOOL Show);
35. 35
SPACE바가 눌렸다면 마지막 줄에 이동할 때 까지 블록을 아래로 이동시
켜야 합니다.
if (kbhit()) { // 키가 눌렸는지 확인
ch = getch();
…
else if(ch == SPACE) {
while(MoveDown()==FALSE)
{;}
return TRUE;
}
void PrintBrick(BOOL Show);
36. 36
void TestFull()
{
int i,x,y,ty;
for (i=0;i<4;i++) {
board[nx+Shape[brick][rot][i].x][ny+Shape[brick][rot][i].y]=BRICK;
}
for (y=1;y<BH+1;y++) {
for (x=1;x<BW+1;x++) {
if (board[x][y] != BRICK)
break;
}
void TestFull();