티스토리 뷰

사용언어) C++

GitHub) https://github.com/Hong-Study/MineSweeper

 

GitHub - Hong-Study/MineSweeper

Contribute to Hong-Study/MineSweeper development by creating an account on GitHub.

github.com

  게임의 전체적인 과정은 다 만들었다. 그런데 친구에게 게임을 보여주니까, 빠른 속도로 이동할 때 화면이 끊기는 깜빡임이 발생해서 아쉽다는 얘기를 들었다. 그래서 친구가 깜빡임을 없애기 위해서 더블 버퍼링이라는 기술을 한번 추가해 보는게 어떻겠냐고 추천을 해서, 넣어보게 되었다.

 


 

깜빡임 발생 이유는? 

  보통 CMD 에서 우리가 std::cout 로 출력을 하게 되면 하나의 화면에 쓰기가 바로 실행이 된다. 그렇다 보니 빠른속도로 cout와 system("cls")가 실행이 되면 빠른 속도로 쓰기와 지우기가 하나의 화면에서 실행되면서 깜빡임이 발생하게 된다.

  • system("cls") 명령어로 콘솔을 지우고 count로 다시 쓰는 방식 사용
  • 따라서 더블 버퍼링 기술 사용

 


더블 버퍼링이란? 

  더블 버퍼링이란 말 그대로 버퍼를 두개 사용하는 것이다. 화면 출력 버퍼 1개, 출력 예비 버퍼 1개. 이렇게 총 2개의 버퍼를 이용하여 출력하는 방식을 더블 버퍼링이라고 한다. 아래의 그림을 통해서 설명하겠다.

더블 버퍼링 이미지

  1.  먼저 1번 버퍼를 출력하는 프로그램에서, 다음 실행될 그림을 예비 버퍼 2번에 그리기 시작한다.
  2.  예비 버퍼 2번과 출력 버퍼인 1번을 swap 하여 2번 버퍼를 출력버퍼로 사용한다.
  3.  예비 버퍼가 된 1번과 출력 버퍼가 된 2을 다시 1번으로 가서 실행하면 이것이 더블 버퍼링이다.

이런 방식으로 작동하는 더블 버퍼링을 적용한 코드는 아래에 있다.

int g_nScreenIndex;
HANDLE g_hScreen[2];

void GameBoard::ScreenInit()	// 스크린 초기화
{
	CONSOLE_CURSOR_INFO cci;

	//화면 버퍼 2개를 만든다.
	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);

	//커서를 숨긴다.
	cci.dwSize = 1;
	cci.bVisible = FALSE;
	SetConsoleCursorInfo(g_hScreen[0], &cci);
	SetConsoleCursorInfo(g_hScreen[1], &cci);
}

void GameBoard::ScreenFlipping()	// 두번째 스크린과 첫번째 스크린 교환
{
	SetConsoleActiveScreenBuffer(g_hScreen[g_nScreenIndex]);
	g_nScreenIndex = !g_nScreenIndex;
}

void GameBoard::ScreenClear()	// 사용한 스크린 비우는 함수
{
	for (int i = 0; i < Map_size; i++) {
		COORD Coor = { i, 0 };
		DWORD dw;
		FillConsoleOutputCharacter(g_hScreen[g_nScreenIndex], ' ', 80 * 25, Coor, &dw);
	}
}

void GameBoard::ScreenRelease()		// 마지막 삭제.
{
	CloseHandle(g_hScreen[0]);
	CloseHandle(g_hScreen[1]);
}

void GameBoard::ScreenPrint(int x, int y, std::string s)	// 두번째 스크린에 그림 그리는 함수
{
	DWORD dw;
	COORD CursorPosition = { x, y };
	SetConsoleCursorPosition(g_hScreen[g_nScreenIndex], CursorPosition);
	WriteFile(g_hScreen[g_nScreenIndex], s.c_str(), s.size(), &dw, NULL);
}

void GameBoard::Render()	// 두번째 스크린에 그림 그리기 준비하는 함수
{
	ScreenClear();
	std::string s;
	for (int i = 0; i < Map_size; ++i) {
		for (int j = 0; j < Map_size; ++j) {
			if (i == y && j == x)
				s += "☆";
			else if (Maps[i][j].Visible) {
				if (Maps[i][j].Type == Map::NOTBOMB) {
					if (Maps[i][j].count == 0)
						s += " ";
					else
						s += std::to_string(Maps[i][j].count);
						s += " ";
				}
				else if (Maps[i][j].Type == Map::FLAG)
					s += "◎";
				else
					s += "ㅁ";
			}
			else {
				s += "■";
			}
		}
		s += "\n";
	}
	ScreenPrint(0, 0, s);
	ScreenFlipping();
}

● 적용하는 부분에서 WCHAR 부분을 정확히 이해 못해서 살짝 헷갈렸지만, C++에서 CMD에서 사용할 때는 이런식으로 string 클래스의 c_str()을 이용하면 사용할 수 있다. 물론 API 공부도 살짝 필요하다..

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함