학교 팀프로젝트로 만든 게임이 있다.
콘솔창에서 3D 렌더링을 구현한 게임이다.
하지만 게임에는 심각한 문제점이 있었다.
FPS가 너무 낮았다.
한번에 몇백문자들을 콘솔창에 출력하려다보니 출력하는데 시간이 걸릴 수 밖에 없었고, 그로인해 한 프레임을 그리는데 너무 오래 걸렸다.
그래서 해결 방법을 찾다가, 고전 게임에서 더블 버퍼링이라는 방식을 사용한다는 것을 알게 되었다.
이는 아직 수업시간에 배워본적 없는 Win API를 사용하여 구현되었기에 나는 일단 제작을 시도해봤다. 코드 자체는 인터넷에 이미 많이 존재했다.
HANDLE hConsole;
HANDLE g_hScreen[2];
bool screenIndex;
void InitConsoleBuffer()
{
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof(cfi);
cfi.nFont = 0;
cfi.dwFontSize.X = 8; // Width of each character in the font
cfi.dwFontSize.Y = 8; // Height
SetCurrentConsoleFontEx(hConsole, FALSE, &cfi);
screenIndex = false;
CONSOLE_CURSOR_INFO cci;
g_hScreen[0] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
g_hScreen[1] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
CONSOLE_SCREEN_BUFFER_INFO consoleInfo{ 0, };
GetConsoleScreenBufferInfo(hConsole, &consoleInfo);
//system("mode con: cols=960 lines=540");
consoleInfo.srWindow.Left = 0;
consoleInfo.srWindow.Top = 0;
consoleInfo.srWindow.Bottom = 540; // 콘솔의 Height
consoleInfo.srWindow.Right = 960; // 콘솔의 Width
// 커서를 숨긴다.
cci.dwSize = 1;
cci.bVisible = FALSE;
SetConsoleCursorInfo(g_hScreen[0], &cci);
SetConsoleScreenBufferSize(g_hScreen[0], consoleInfo.dwSize); // 화면 버퍼 크기 설정
SetConsoleWindowInfo(g_hScreen[0], TRUE, &consoleInfo.srWindow); // 콘솔 설정
SetConsoleCursorInfo(g_hScreen[1], &cci);
SetConsoleScreenBufferSize(g_hScreen[1], consoleInfo.dwSize); // 화면 버퍼 크기 설정
SetConsoleWindowInfo(g_hScreen[1], TRUE, &consoleInfo.srWindow); // 콘솔 설정
}
이건 더블 버퍼 사용을 위해 초기 설정을 해주는 스크립트다.
void FlipConsoleBuffer()
{
SetConsoleActiveScreenBuffer(g_hScreen[screenIndex?1:0]);
screenIndex = !screenIndex;
}
void ClearConsole()//재사용전 클리어
{
COORD Coord = { 0, 0 };
DWORD dw;
FillConsoleOutputCharacter(hConsole, ' ', (SCREEN_HEIGHT+50) * FOV, Coord, &dw);
}
void PrintConsoleBuffer(int x, int y, std::string s)
{
DWORD dw;
COORD CursorPosition = { x, y };
SetConsoleCursorPosition(g_hScreen[screenIndex ? 1 : 0], CursorPosition);
WriteFile(g_hScreen[screenIndex ? 1 : 0], s.c_str(), strlen(s.c_str()), &dw, NULL);
}
void RenderConsole(std::string s)
{
//ClearConsole();
PrintConsoleBuffer(0, 0, s);
FlipConsoleBuffer();
}
void ReleaseConsoleBuffer()
{
CloseHandle(g_hScreen[0]);
CloseHandle(g_hScreen[1]);
}
다만 이 방식으로 구현하니 화면이 짤린다는 문제가 생겼다.
> (화면을 잠시 멈춘뒤 스크롤을 내리고 올리면 보이는 화면, 의도된 것과 다르게 일부분만이 출력된다.)
무엇이 문제인지 찾아봤지만 다 아니였다.
system("mode con: cols=960 lines=540");
GetConsoleScreenBufferInfoEx(hConsole, &consoleInfo);
consoleInfo.srWindow.Left = 0;
consoleInfo.srWindow.Top = 0;
consoleInfo.srWindow.Bottom = 400;
consoleInfo.srWindow.Right = 960;
한참을 해맨 결과 정답을 찾았다.
void InitConsoleBuffer()
{
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof(cfi);
cfi.nFont = 0;
cfi.dwFontSize.X = 8; // Width of each character in the font
cfi.dwFontSize.Y = 8; // Height
SetCurrentConsoleFontEx(hConsole, FALSE, &cfi);
screenIndex = false;
CONSOLE_CURSOR_INFO cci;
g_hScreen[0] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
g_hScreen[1] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo{ 0, };
GetConsoleScreenBufferInfoEx(hConsole, &consoleInfo);
//system("mode con: cols=960 lines=540");
consoleInfo.srWindow.Left = 0;
consoleInfo.srWindow.Top = 0;
consoleInfo.srWindow.Bottom = 400; // 콘솔의 Height
consoleInfo.srWindow.Right = 960; // 콘솔의 Width
// 커서를 숨긴다.
cci.dwSize = 1;
cci.bVisible = FALSE;
SetConsoleScreenBufferInfoEx(hConsole, &consoleInfo);
SetConsoleCursorInfo(g_hScreen[0], &cci);
SetConsoleScreenBufferInfoEx(g_hScreen[0], &consoleInfo); // 콘솔 설정
ShowWindow(GetConsoleWindow(), SW_MAXIMIZE);
SetConsoleCursorInfo(g_hScreen[1], &cci);
SetConsoleScreenBufferInfoEx(g_hScreen[1], &consoleInfo); // 콘솔
ShowWindow(GetConsoleWindow(), SW_MAXIMIZE);
}
함수가 틀렸었다.
세 버퍼 모두에게 함수 크기 최대화도 먼저 해줘야 했고, 실제로는 Ex함수를 사용해야 제대로 크기 설정이 들어갔다.
약간의 문제가 남아있긴 하지만, 충분히 괜찮은 모습이다.
'C++과 C#' 카테고리의 다른 글
C#에는 왜 string말고도 stringbuilder가 존재할까? (2) | 2024.09.15 |
---|