글 수 18,796
#include <time.h>
#include <iostream>
#include <random>
#include <Windows.h>
#include <conio.h>
using namespace std;
// Map Width (constexpr)
constexpr int MAP_WIDTH = 12;
int up, down, lft, rht, R, space, score;
// Map Height (constexpr)
constexpr int MAP_HEIGHT = 22;
// Rectangle 구조체
struct stRect
{
int nWidth;
int nHeight;
};
// Key Code
enum eKeyCode
{
KEY_UP = 72, // 방향키 ↑
KEY_DOWN = 80, // 방향키 ↓
KEY_LEFT = 75, // 방향키 ←
KEY_RIGHT = 77, // 방향키 →
KEY_SPACE = 32, // 스페이스바
KEY_R = 114, // R키
};
// 콘솔 관련 설정 값을 가지고 있을 구조체
struct stConsole
{
// Console Handler
HANDLE hConsole;
// Console Rect Data
stRect rtConsole;
// Console Buffer Handler
HANDLE hBuffer[2];
// Current Console Buffer Index
int nCurBuffer;
stConsole()
: hConsole(nullptr), hBuffer{ nullptr, }, nCurBuffer(0)
{}
};
// Origin Map
int ORIGIN_MAP[MAP_HEIGHT][MAP_WIDTH] =
{
{1,1,1,1,1,1,1,1,1,1,1,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,},
};
// Block Type
const char BLOCK_TYPES[][4] =
{
" ", // 빈 공간
"▣", // 프레임
"□", // 블록
"★"
};
// Console Data
//stConsole g_console;
stConsole console;
/**
@brief Rendering function
@param nXOffset X Offset (그림을 그릴 때 왼쪽에서부터)
@param nYOffset Y Offset (그림을 그릴 때 위쪽에서부터)
@return
*/
void Render(int nXOffset = 0, int nYOffset = 0)
{
COORD coord{ 0, };
int nXAdd = 0;
DWORD dw = 0;
// Map 그리기
{
for (int nY = 0; nY < MAP_HEIGHT; ++nY)
{
nXAdd = 0;
for (int nX = 0; nX < MAP_WIDTH; nX++)
{
coord.X = nXAdd + nXOffset;
coord.Y = nY + nYOffset;
// 커서의 위치를 이동
SetConsoleCursorPosition(console.hBuffer[console.nCurBuffer], coord);
// 출력 버퍼의 해당 커서 위치에 출력
WriteFile(console.hBuffer[console.nCurBuffer], BLOCK_TYPES[ORIGIN_MAP[nY][nX]], sizeof(BLOCK_TYPES[ORIGIN_MAP[nY][nX]]), &dw, NULL);
// X 위치 이동
nXAdd += 2;
// 굴림체 폰트에서는 특수문자의 경우 특수문자 하나가 띄어쓰기 2개와 크기가 같습니다.
// (보이는 것만 그렇고 실제로는 특수문자도 공간을 하나만 차지합니다.)
// 그렇기 때문에 띄어쓰기가 나올 경우 2칸을 움직이게 합니다.
// if (ORIGIN_MAP[nY][nX] == 0)
// nXAdd += 1;
}
}
char buf[110] = {0};
sprintf(buf, "%d%d%d%d%d%d", up, down, lft, rht, space, R);
SetConsoleCursorPosition(console.hBuffer[console.nCurBuffer], { 4, 23 });
WriteFile(console.hBuffer[console.nCurBuffer], buf, 10, &dw, NULL);
sprintf(buf, "SCORE : %04d", score);
SetConsoleCursorPosition(console.hBuffer[console.nCurBuffer], { 4, 24 });
WriteFile(console.hBuffer[console.nCurBuffer], buf, 10, &dw, NULL);
}
}
void InitGame(bool bInitConsole = true)
{
srand(time(NULL));
// Initialize Console Data
if (bInitConsole)
{
// 현재 콘솔의 핸들을 받아옵니다.
console.hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// 현재 콘솔 버퍼의 인덱스를 0으로 초기화
console.nCurBuffer = 0;
// 콘솔 관련 설정
CONSOLE_CURSOR_INFO consoleCursor{ 1, FALSE }; // 콘솔의 커서 깜빡임을 제거합니다.
CONSOLE_SCREEN_BUFFER_INFO consoleInfo{ 0, };
GetConsoleScreenBufferInfo(console.hConsole, &consoleInfo);
consoleInfo.dwSize.X = 20; // 콘솔의 Width
consoleInfo.dwSize.Y = 30; // 콘솔의 Height
// 콘솔의 크기를 다시 계산 (나중에 그림 그릴때 사용)
console.rtConsole.nWidth = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left;
console.rtConsole.nHeight = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top;
// 콘솔의 첫번째 화면 버퍼 생성
console.hBuffer[0] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleScreenBufferSize(console.hBuffer[0], consoleInfo.dwSize); // 화면 버퍼 크기 설정
SetConsoleWindowInfo(console.hBuffer[0], TRUE, &consoleInfo.srWindow); // 콘솔 설정
SetConsoleCursorInfo(console.hBuffer[0], &consoleCursor); // 콘솔의 커서 설정
// 콘솔의 두번째 화면 버퍼 생성
console.hBuffer[1] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleScreenBufferSize(console.hBuffer[1], consoleInfo.dwSize);
SetConsoleWindowInfo(console.hBuffer[1], TRUE, &consoleInfo.srWindow);
SetConsoleCursorInfo(console.hBuffer[1], &consoleCursor);
}
}
void DestroyGame()
{
if (console.hBuffer[0] != nullptr)
{
CloseHandle(console.hBuffer[0]);
}
if (console.hBuffer[1] != nullptr)
{
CloseHandle(console.hBuffer[1]);
}
}
// 화면 클리어
void ClearScreen()
{
COORD pos{ 0, };
DWORD dwWritten = 0;
unsigned size = console.rtConsole.nWidth * console.rtConsole.nHeight;
// 콘솔 화면 전체를 띄어쓰기를 넣어 빈 화면처럼 만듭니다.
FillConsoleOutputCharacter(console.hConsole, ' ', size, pos, &dwWritten);
SetConsoleCursorPosition(console.hConsole, pos);
}
// 버퍼 스왑
void BufferFlip()
{
// 화면 버퍼 설정
SetConsoleActiveScreenBuffer(console.hBuffer[console.nCurBuffer]);
// 화면 버퍼 인덱스를 교체
console.nCurBuffer = console.nCurBuffer ? 0 : 1;
}
void InputKey()
{
bool keyState[256] = {false}; // 모든 키의 상태를 저장할 배열
DWORD dw = 0;
int nKey = 0;
if (_kbhit() > 0)
{
nKey = _getch();
switch (nKey)
{
case eKeyCode::KEY_UP: // 방향키 위를 눌렀을 때
{
if( up ) break;
up = 1;
break;
}
case eKeyCode::KEY_DOWN: // 방향키 아래를 눌렀을 때
{
if( down ) break;
down = 1;
break;
}
case eKeyCode::KEY_LEFT: // 방향키 왼쪽을 눌렀을 때
{
if( lft ) break;
lft = 1;
break;
}
case eKeyCode::KEY_RIGHT: // 방향키 오른쪽을 눌렀을 때
{
if( rht ) break;
rht = 1;
break;
}
case eKeyCode::KEY_SPACE: // 스페이스바를 눌렀을 때
{
if( space ) break;
space = 1;
while( ORIGIN_MAP[rand()%20+1][rand()%10+1] );
int temp = rand()%2+2;
ORIGIN_MAP[rand()%20+1][rand()%10+1] = temp;
break;
}
case eKeyCode::KEY_R: // R키를 눌렀을 때
{
if( R ) break;
R = 1;
break;
}
}
}
// 키 뗌 감지
for (int key = 0; key < 256; key++) {
if (GetAsyncKeyState(key) & 0x8000) { // 키가 눌린 상태
if (!keyState[key]) { // 키가 이전에 눌리지 않았다면
keyState[key] = true; // 눌린 상태로 변경
}
} else {
if (keyState[key]) { // 키가 눌렸던 상태
keyState[key] = false; // 눌리지 않은 상태로 변경
}
}
}
if( !keyState[38] ) up = 0;
if( !keyState[40] ) down = 0;
if( !keyState[37] ) lft = 0;
if( !keyState[39] ) rht = 0;
if( !keyState[32] ) space = 0;
if( !keyState[82] ) R = 0;
}
void Process()
{
for(int i = 1 ; i < 22 ; i++) for(int j = 1 ; j < 12 ; j++ )
if( ORIGIN_MAP[i][j] == 2 ) score--;
else if( ORIGIN_MAP[i][j] == 3 ) score++;
}
int main(void)
{
InitGame();
char chBuf[256] = { 0, };
COORD coord{ 0,0 };
DWORD dw = 0;
while (true)
{
InputKey();
Render(3, 1);
Process();
ClearScreen();
BufferFlip();
Sleep(1);
}
DestroyGame();
return 0;
}