0. 서론

우리는 아주 간단한 세가지 함수를 다루는 방법을 배웠습니다.

다만 간단하지만 아주 강력한 기능들입니다.

이를 통하여 간단한 게임을 한가지 만들어보고자 합니다.

 

1. 설계

규칙은 아주 간단합니다.

 

1. 랜덤한 위치에 별이 생성된다.

2. 캐릭터가 별에 닿으면 점수가 오르고 별이 사라진다.

3. 특정 점수까지 도달할때까지 1~2를 반복한다.

 

위의 규칙을 바탕으로 게임을 만들어 볼겁니다.

 

 

2. 구현

2-0. 완성된 코드

#include<iostream>
#include<conio.h>
#include<WIndows.h>

// 방향키
#define UP 72
#define LEFT 75
#define RIGHT 77
#define DOWN 80

//좌표 출력
#define POS 30

using namespace std;

void gotoxy(int x, int y) {
	COORD pos = { x, y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

int player_x, player_y;
int object_x, object_y;
int score = 0;
int star = 0;

void make_star() {
	srand(time(NULL));
	object_x = rand() % 20;
	object_y = rand() % 20;
	gotoxy(object_x, object_y);
	printf("★");
}

void draw_player() {
	gotoxy(player_x, player_y);
	printf("@");
}


void move(int input) {
	switch (input) {
	case DOWN:
		player_y++;
		break;
	case UP:
		player_y--;
		break;
	case LEFT:
		player_x--;
		break;
	case RIGHT:
		player_x++;
	}
}

void check() {
	if (object_x - player_x > -2 && object_x - player_x < 2 && object_y == player_y) {
		score++;
		star = 0;
		gotoxy(object_x, object_y);
		printf("      ");
	}
}

int main(void) {
	player_x = player_y = 20;

	int c;
	while (1) {
		gotoxy(POS, POS);
		printf("player : (%d, %d)    \n", player_x, player_y);
		gotoxy(POS, POS-1);
		printf("star   : (%d, %d)    \n", object_x, object_y);
		gotoxy(POS, POS-2);
		printf("score  : %d", score);



		draw_player();
		/* 별이 없다면 */
		if (!star) {
			make_star();
			star = 1;
		}

		if (_kbhit()) {
			/* 224 키보드 방향키값 제거 */
			do { c = _getch(); } while (c != 224);
			/* 기존 도형을 삭제*/
			gotoxy(player_x, player_y);
			printf("  ");
			/* 이동 처리 */
			move(_getch());
		}

		check();

	}
}

먼저 소스 코드를 모두 공개했습니다.

여기서 하나하나 요소를 모두 살펴보면서 소스코드를 분석해보겠습니다.

 

 

2-1. 요소를 그리기

void gotoxy(int x, int y) {
	COORD pos = { x, y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

앞서 구현한 위의 gotoxy함수를 활용합니다.

위를 통하여 해당하는 위치에 원하는 요소들을 그릴 수 있습니다.

이번에 필요한 요소는 별과 캐릭터를 그리는 것이 되겠습니다.
이것을 기본으로 하나하나 게임을 설계해 봅시다.

 

2-2. 캐릭터의 이동

while(1){
  ...
  draw_player();
  ...
  if (_kbhit()) {
              /* 224 키보드 방향키값 제거 */
              do { c = _getch(); } while (c != 224);
              /* 기존 도형을 삭제*/
              gotoxy(player_x, player_y);
              printf("  ");
              /* 이동 처리 */
              move(_getch());
          }
  ...
}

먼저 key를 어떻게 받느냐에 따른 이동처리를 해줘야 합니다.

위 키를 누르면 위로 이동하도록, 아래 키를 누르면 아래로 이동하도록 만들어 줘야겠습니다.

 

1. 먼저 방향키 값을 제거하고,

2. gotoxy를 통하여 플레이어의 위치로 이동한 뒤 공백을 출력하여 기존 플레이어 도형을 삭제합니다.

3. 이후 함수를 통하여 이동 처리를 한 뒤 반복문을 통하여 다시 플레이어를 그려줍니다.

 

void move(int input) {
	switch (input) {
	case DOWN:
		player_y++;
		break;
	case UP:
		player_y--;
		break;
	case LEFT:
		player_x--;
		break;
	case RIGHT:
		player_x++;
	}
}

플레이어의 이동 처리를 하는 move 함수는 아주 간단합니다.

입력된 값에 따라서 플레이어의 좌표 값만 수정해주는 방식입니다.

다만 주의하여야 할 점은 일반적인 좌표계와 다르게 아래쪽이 증가하는 방향입니다.

(옜날 컴퓨터가 위에서 아래로 출력하는 것을 본적 있다면 쉽게 이해하실 겁니다.)

 

화면좌표계는 왼쪽 상단 위가 (0, 0) 이고 아래로 내려갈 수록 y좌표가 증가합니다.

따라서 DOWN, UP에 있어서는 일반적인 좌표계와 반대로 DOWN에서는 증가, UP에서는 감소를 시켜줍니다.

 

void draw_player() {
	gotoxy(player_x, player_y);
	printf("@");
}

캐릭터가 이동하였다면 그려줘야겠죠?

그냥 현재 플레이어의 좌표로 가서 플레이어의 캐릭터 모양인 "@"을 출력해줄 뿐입니다.

 

2-3. 별의 생성

void make_star() {
	srand(time(NULL));
	object_x = rand() % 20;
	object_y = rand() % 20;
	gotoxy(object_x, object_y);
	printf("★");
}

별의 생성도 아주 간단합니다.

srand() 함수를 통하여 시간에 따른 시드를 부여한 뒤,

(0, 0) ~ (20, 20) 사이에 별의 값을 부여하고 그 위치에 별을 출력하면 끝입니다.

 

2-4. 점수 획득

void check() {
	if (object_x - player_x > -2 && object_x - player_x < 2 && object_y == player_y) {
		score++;
		star = 0;
		gotoxy(object_x, object_y);
		printf("      ");
	}
}

마지막으로 플레이어가 별에 다가가면 점수를 획득해야겠죠?

별의 크기가 화면에서 출력할 때 2칸정도 크기를 잡아먹습니다.

따라서 별의 x축과 플레이어의 y축의 차이가 2 이내일 경우,

별과 플레이어가 같은 높이에 있을 경우(y값이 같음)

점수를 올려줍니다.

star = 0;을 통하여 star 변수를 0으로 만들어 main함수에서 별을 다시 생성할 수 있도록 해줍니다.

또한 별의 위치로 이동하여 공백을 출력함으로 별을 지워줍니다.

 

2-5. 마무리

자 이제 필수 요소들을 모두 살펴봤으니 처음 봤던 소스코드를 다시 한번 살펴보도록 하겠습니다.

자잘한 것들은 주석을 달아놓을테니 확인해보세요.

#include<iostream>
#include<conio.h>
#include<WIndows.h>

// 방향키
#define UP 72
#define LEFT 75
#define RIGHT 77
#define DOWN 80

/* 아래 위치에 별과 플레이어, 점수 등을 표시하기 위하여 선언했습니다. */
#define POS 30

using namespace std;

/* 해당 좌표로 이동하는 함수입니다. */
void gotoxy(int x, int y) {
	COORD pos = { x, y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

/* 플레이어와 별의 위치를 기억하기 위하여 선언한 변수입니다.*/
int player_x, player_y;
int object_x, object_y;

/* 점수와 게임 화면에 별이 있는지 확인하기 위한 변수입니다. */
int score = 0;
int star = 0;

/* 위에서 다루었던 별을 만드는 함수입니다. */
void make_star() {
	srand(time(NULL));
	object_x = rand() % 20;
	object_y = rand() % 20;
	gotoxy(object_x, object_y);
	printf("★");
}

/* 위에서 다루었던 플레이어의 위치를 표시하는 함수입니다. */
void draw_player() {
	gotoxy(player_x, player_y);
	printf("@");
}

/* 위에서 다루었던 입력에 따른 플레이어 좌표 변환 함수입니다.*/
void move(int input) {
	switch (input) {
	case DOWN:
		player_y++;
		break;
	case UP:
		player_y--;
		break;
	case LEFT:
		player_x--;
		break;
	case RIGHT:
		player_x++;
	}
}

/* 위에서 다루었던 플레이어가 별을 획득했는지(별에 닿였는지) 여부를 확인하는 함수입니다. */
void check() {
	if (object_x - player_x > -2 && object_x - player_x < 2 && object_y == player_y) {
		score++;
		star = 0; /* 별 상태를 0으로 만들어 다시 별이 생성되게끔 합니다. */
		gotoxy(object_x, object_y);
		printf("      ");
	}
}

int main(void) {
    /* 초기 플레이어 위치는 20으로 설정했으나 얼마로 설정하든 상관없습니다. */
	player_x = player_y = 20;
	int c;
	while (1) {
        /* 플레이어와 별, 점수를 나타내기 위한 출력문입니다. */
        /* POS의 위치에서 차례대로 출력합니다. */
		gotoxy(POS, POS);
		printf("player : (%d, %d)    \n", player_x, player_y);
		gotoxy(POS, POS-1);
		printf("star   : (%d, %d)    \n", object_x, object_y);
		gotoxy(POS, POS-2);
		printf("score  : %d", score);
        
        /* 플레이어를 그립니다. */
		draw_player();
        
		/* 별을 획득하여 별이 없을 경우 별을 그립니다. */
		if (!star) {
			make_star();
			star = 1; // 별을 그리고 별 상태를 1로 바꿉니다.
		}
		
		if (_kbhit()) {
			/* 224 키보드 방향키값 제거 */
			do { c = _getch(); } while (c != 224);
			/* 기존 도형을 삭제*/
			gotoxy(player_x, player_y);
			printf("  ");
			/* 이동 처리 */
			move(_getch());
		}
		check();
	}
}

3. 실행 화면

점수도 잘 오르고 플레이어와 별의 위치 또한 잘 나타내고 있는 모습이 보입니다.

 

다만 아쉬운 점은 소스코드에 종료 버튼을 넣지 않아서 컨트롤+C를 통한 콘솔 종료를 해야한다는 점이네요 ㅜ

 

커서도 많이 신경쓰일 수 있구요!

 

이 부분에 대해서는 각자 숙제로 맡기겠습니다~

0. 서론

컴퓨터가 발전하고 여러가지 입출력 장치가 생겨났습니다.

오늘 살펴볼 것은 강력한 입력 장치 중 하나인 키보드를 활용한 방법입니다.

 

1. getch()를 통한 키값 확인

 

키보드 입력 값 출력

위의 사진 처럼 키보드로 입력할 경우 키보드에 해당하는 문자를 출력하고 입력값이 얼마인지 출력하도록 했습니다.

 

ESC키를 누르게 되면 프로그램은 종료를 합니다.

 

다만 재미있는 점은 아래와 같습니다.

 

특수한 입력에 대한 출력

먼저, 위의 출력을 먼저 살펴보겠습니다.

? 224 이후 H: 72 와 같은 패턴으로 4가지가 나옵니다.

이는 방향키에 대한 출력입니다.

 

방향키를 비롯한 몇몇 입력들은 1바이트로 처리되는 아스키코드와 다르게 확장 아스키 코드를 사용하기 때문에 저렇게 두번의 변환을 통하여 표현됩니다.

 

아래의 : 0 이후 ; : 59와 같은 패턴은 F1~F5번을 입력했을 때 나타나는 결과입니다.

 

이를 통하여 우리는 일반적인 키보드 입력을 처리하는 방법과 특수한 키를 처리하는 방법 두가지를 익혔습니다.

 

위의 사진에서 사용한 코드는 아래와 같습니다.

#include<iostream>
#include<conio.h>

using namespace std;

/* 키입력 테스트 */
int main(void) {
	int key;
	
	while (1) {
		key = _getch();
		cout << (char)key << ": " << key << endl;
		if (key == 27) {
			cout << "ESC";
			break;
		}
	}
}

2. kbhit()을 통한 입력 확인

kbhit()은 키 입력이 있는지 없는지 확인하는 함수입니다.

getch()는 키 입력이 생길 때 까지 기다리는 반면,

kbhit()은 입력버퍼를 확인하여 당장에 있으면 true, 없으면 false를 반환하는 함수입니다.

즉, 기다림이 없습니다.

 

쉽게 표현하자면 getch()은 내가 무언가를 입력해야 다음으로 진행하기 때문에 턴제 게임,

kbhit()은 입력이 있으면 하고 없으면 안하는 실시간 게임과 같은 효과를 줍니다.

 

kbhit()이 얼마나 중요성이 이제 실감이 나실까요?

다음의 캡처를 살펴보겠습니다.

 

getch()

위의 코드에서 while문이 시작할 때 "while문 시작.."이라는 문자열만 출력하도록 추가했습니다.

내가 무언가 입력을 해야만 다음 단계로 처리가 이루어집니다.

 

여기서 kbhit()을 이용하여 코드를 수정해보겠습니다.

#include<iostream>
#include<Windows.h> // Sleep() 함수를 사용하기 위하여 추가
#include<conio.h>

using namespace std;

/* kbhit을 추가한 키입력 테스트 */
int main(void) {
	int key;
	
	while (1) {
		if (_kbhit()) {
			key = _getch();
			cout << (char)key << ": " << key << endl;
			if (key == 27) {
				cout << "ESC";
				break;
			}
		}
		else {
			cout << "입력대기...\n";
			Sleep(100); //Sleep을 넣지 않으면 너무 빨라 확인하기 힘들다.
		}
	}
}

 

while문 아래에 if문을 추가하여 키보드 입력이 있으면 이전과 같이 입력 값을 출력하도록 하고,

만약 입력이 없다면 "입력대기..."라는 문자열을 출력하도록 만들었습니다.

 

실행해본다면 다음과 같이 나타납니다.

kbhit() 이 없었을 경우에는 입력을 하지 않으면 함수의 흐름 또한 멈춥니다.

kbhit()을 넣었을 때는 입력을 하지 않아도 프로그램은 다른 작업을 계속 수행하며 함수가 흘러갑니다.

 

3. 정리

우리는 getch()를 통하여 키보드 입력을 처리하는 방법과,

kbhit()을 통하여 실시간 상호작용을 할 수 있는 기반을 다졌습니다!

 

참고로 kbhit은 KeyBoard hit의 줄임말이라고 합니다.

함수를 기억할 때 도움이 되셨으면 좋겠네요.

 

 

 

 

0. 개요

콘솔 화면에서 게임을 만들기 위해서는 콘솔 화면에 원하는 위치에 대상을 그릴 수 있어야 합니다.

 

이를 위해 만들 기본적인 함수 중 하나가 이번에 소개할 gotoxy 함수입니다.

 

 

1. 동작

gotoxy 활용

gotoxy함수를 사용하여 위와 같은 연출을 낼 수 있습니다.

 

1. 프로그램이 시작되고 아무 키나 입력 받는다

2. HELLO!, NICE!를 두줄에 걸쳐 출력한다.

3. 화살표를 통하여 H를 소문자로 바꾼다

4. HELLO!를 지우고 :) 이모티콘을 출력한다.

 

아래에 코드를 살펴보면서 위의 네가지의 동작을 분석해보겠습니다.

 

3. 코드 및 분석

#include<iostream>
#include<windows.h> //gotoxy를 위한 헤더 
#include<conio.h>   //_getch()를 위한 헤더

using namespace std;

void gotoxy(int x, int y) {
	COORD pos = { x, y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

int main(void) {
	printf("Press Any Key...");
	_getch();//키 입력을 대기합니다.
    
    /* HELLO!, NICE! 문자열을 출력 */
	gotoxy(10, 10);
	printf("HELLO!\n");
    
	gotoxy(10, 11);
	printf("NICE!\n");
    
	Sleep(1000); // 잠시 쉬었다가..
	gotoxy(8, 10); // HELLO 앞에 화살표 출력
	printf("→");
    
	Sleep(1000); //잠시 쉬었다가..
	gotoxy(10, 10); // 소문자로 변경
	printf("h"); // 문자열 위에 출력하면 덮어쓰기가 됨을 확인 가능.
    
	Sleep(1000);
    /* 공백을 활용하여 문자를 지움 */
	for (int x = 15; x > 9; x--) {
		gotoxy(x, 10);
		printf(" ");
		Sleep(500);
	}
    
    /* :) 이모티콘 출력 */
	gotoxy(10, 10);
	printf(":");
	Sleep(500);
	printf(")");
	Sleep(1000);
	gotoxy(20,20);
}

 

* COORD 구조체

 : short x, short y를 구조체 멤버로 가진 좌표 구조체 입니다.

 

* SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);

 : 콘솔 마우스 커서의 위치를 조절하는 함수, 표준 출력 핸들을 통하여 x,y좌표를 가진 pos 구조체 위치로 이동합니다.

   표준 출력은 화면(콘솔)에 해당됩니다.

 

1. 프로그램이 시작되고 아무 키나 입력 받는다

-> _getch()를 활용하여 키 입력을 대기합니다.

-> _getch()는 입력받은 키의 값을 반환하는 함수입니다.

 

2. HELLO!, NICE!를 두줄에 걸쳐 출력한다.

-> gotoxy를 통하여 위치를 지정하여 출력합니다.

 

3. 화살표를 통하여 H를 소문자로 바꾼다

-> 출력된 화면 위에 출력한다면 교체된다.

 

4. HELLO!를 지우고 :) 이모티콘을 출력한다.

-> 연출의 방법 중 하나로 사용된다.

 

 

4. 정리

커서 이동 함수를 통하여 콘솔화면에 원하는 위치에 출력할 수 있는 gotoxy함수를 작성해 보았습니다.

또한 키의 입력을 대기 위하여 getch() 함수를 활용할 수 있는 것까지 확인했습니다.

+ Recent posts