본문 바로가기

Programming Language/C, C++

[Snake Game] 1. 맵과 플레이어 출력하기


1. 맵과 플레이어 출력하기



0. Intro

최종 결과물의 모습은 대략 아래와 비슷할 것이다.


■는 맵의 테두리이고, ▲은 뱀(플레이어)이며, ♥은 먹이이다. 오른쪽에 배치된 글씨들은 현재 게임 상태를 나타내는 것으로, 기본적인 뱀게임 시스템을 모두 구현한 다음에 건드릴 부분이다.



1. 맵 출력하기

맵을 출력하는 방법은 특별할 것 없이, printf 구문을 이용해 ■(키보드 한글의 'ㅁ'키를 누른 상태로 한자키를 누르면 사용할 수 있다)와 공백을 적절히 출력하는 것이다. 아래의 코드가 그것이다.


#include <stdio.h>

// ■ ▲ ▼ ◀ ▶ ♥
int main()
{
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■                            ■\n");
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	return 0;
}

실행하면 아래처럼 나온다.



IDE창에서 아래처럼 반듯하게 출력했음에도 불구하고, 상당히 뒤틀린 맵이 출력되었다.



아주 자세히 들여다보면, 콘솔창에서 ■는 일반적인 공백 ' '을 2개 합친 크기란 것을 알 수 있다. 그렇기 때문에, printf구문을 아래처럼 수정해야 한다.

#include <stdio.h>

// ■ ▲ ▼ ◀ ▶ ♥
// map = (30*2) * (27*2)

int main()
{
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	return 0;
}

콘솔창에 적절히 들어가는 맵을 출력하기 위해 크기를 대충 잡아보았다. 그 크기는 세로 30, 가로 54(==27*2)칸이다. 그렇기 때문에 실제 플레이어가 움직일 수 있는 공간은 맵의 테두리를 뺀 28*25칸의 공간이다. 뱀의 몸통 또한 콘솔창의 2칸을 잡아먹을 것임을 간과하지 말아야 한다.


이는 콘솔창과 에디터의 폰트가 달라서 생기는 현상이다. 본인이 콘솔창에 다른 폰트를 사용하고 있다면 그에 맞추어 계산을 해주어야 한다. 



2. setCursorPos

맵은 변하지 않으니 저렇게 간단하게 출력하면 그만이지만, 플레이어의 위치는 계속 바뀌기 때문에 저렇게 무식하게 출력할 수 없다. 즉, 콘솔창 내부의 우리가 원하는 위치에 출력할 수 있어야 한다. 이러한 기능을 지원하는 함수가 아래의 함수이다.


SetConsoleCursorPosition("HANDLER", "POSITION");

이 함수는 헤더파일 <Windows.h>에 정의되어 있다. 윈도우 환경이 아닌 다른 환경에서 개발하는 사람은 본인의 환경에 맞는 이러한 기능을 하는 함수를 구글에서 검색해서 찾아보길 바란다.

저 "POSITION"부분에 COORD 객체형의 값이 들어가야 한다. "HANDLER"부분에도 뭔가 들어가야 하지만 거기까지 알 필요는 없기 때문에 그냥 내가 만들어 둔 아래의 코드를 복사하여 사용하도록 한다.

void setCursorPos(int x, int y) // 콘솔 좌표 위치 지정
{
	COORD pos = { x,y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

위 코드를 복사해서 main()함수 위에 붙여넣는다. 지금까지의 코드는 대충 아래와 같다.


...
void setCursorPos(int x, int y) // 콘솔 좌표 위치 지정
{
	COORD pos = { x,y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

int main()
{
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
...


사족으로, 앞으로의 모든 함수와 변수 이름은 유의미하게, Mixed Case의 형식으로 붙일 것이다. setCursorPos는 set cursor position라는 의미이다. 당황스럽게도, c++ gui 개발에 이용되는 WIN API에 SetCursorPos가 정의되어있다. setCursorPos와 SetCursorPos는 첫 글자가 대문자인지 아닌지의 차이에 의해 컴파일러가 전혀 다른 함수로 인식하지만, 좋은 네이밍이 아님은 확실하다. 하지만 다른 좋은 이름이 생각나지 않기 때문에 setCursorPos라는 이름을 계속 사용하기로 한다.


setCursorPos(x,y)를 호출하면 콘솔창의 (x, y)좌표로 키보드 커서가 움직인다. 여기서 x는 좌우 방향(열)을, y는 상하 방향(행)을 의미한다. 다음 그림을 살펴보자.


맵 테두리의 맨 왼쪽, 맨 위의 칸의 왼쪽은 콘솔창의 좌표로 보았을 때 (0,0)이다. 그 칸과 바로 오른쪽 칸 사이는 콘솔창의 좌표로 보았을 때 (2,0)이다. ■이 콘솔창에서 2칸을 차지한다는 것을 잊지 말자.

바로 아래칸의 왼쪽은 (0, 1)이다. 이 사실을 이용해 맵의 정 중앙의 좌표를 구해보자.




위에서 말했듯이 테두리의 가로에는 30개의 ■가 있고, 세로에는 27개의 ■가 있다. 그렇다면 콘솔창에서 맵의 테두리의 가로 길이는 30*2 == 60이고, 세로 길이는 대충 13이다. 그래서 커서를 (30, 13)에 두고 ■을 출력하면 맵의 정중앙에 출력될 것이다.



뱀의 처음 몸 길이는 3칸이다. 밑으로 2칸 더 출력하여 뱀을 만들도록 한다.


벌써 뭔가 그럴듯한 화면이 생성되었다. 다음에는 저것을 키보드 입력을 통해 움직이는 방법을 살펴볼 것이다.


지금까지의 코드는 아래와 같다.

#include <stdio.h>
#include <Windows.h>
// ■ ▲ ▼ ◀ ▶ ♥
// map = (30*2) * (27*2)

void setCursorPos(int x, int y) // 콘솔 좌표 위치 지정
{
	COORD pos = { x,y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

int main()
{
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■                                                        ■\n");
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	setCursorPos(30, 13);
	printf("■");
	setCursorPos(30, 14);
	printf("■");
	setCursorPos(30, 15);
	printf("■");
	return 0;
}