티스토리 뷰

반응형

2021.09.15 - [C++로 게임 만들기/오목 게임 만들기] - [C++] 오목 게임 만들기 3 - GameManager Class를 만들고 타이틀 화면 그리기

 

[C++] 오목 게임 만들기 3 - GameManager Class를 만들고 타이틀 화면 그리기

2021.09.12 - [C++로 게임 만들기/오목 게임 만들기] - [C++] 오목 게임 만들기 2 - 바둑판을 그리기 위한 DrawMap Class 만들기 [C++] 오목 게임 만들기 2 - 바둑판을 그리기 위한 DrawMap Class 만들기 2021.09...

hgu-can.tistory.com

저번 시간에 콘솔창에 바둑판을 그려봤었어요. 

이번엔 바둑판 위에 타이틀 메뉴를 출력할 것입니다. 


다시 보는 타이틀 화면!

바둑판을 먼저 그린 다음에 메뉴들을 출력하면 위와 같은 화면을 만들 수 있어요. 

 

저번에 만들었던 RunGame 함수에서 cout을 사용해서 메뉴들을 바로 출력해도 되지만 

메뉴만 출력하는 함수를 따로 만들어서 사용하면 함수의 재사용성이 높아져서 훨씬 편해요. 

그래서 메뉴만 출력하는 함수를 만들 거에요. 

 

 

//in GameManager.h

private:
	int MainMenu();

 

GamaManager.h에서 private으로 MainMenu 함수를 선언해주세요. 

반환형이 int인 이유는 switch 문에서 바로 호출할 것이거든요. 

 

 

메뉴는 DrawMap Class의 DrawMidText 함수를 이용해서 출력할 것인데

이름 그대로 string과 출력할 위치를 보내면 자동으로 가운데 정렬해서 출력해주는 함수입니다. 

보다시피 매개변수로는 출력할 string과 위치값 x,y가 필요합니다. 

string은 그냥 " " 안에 쓰면 되지만

위치값은 막연하게 상수를 쓰는 것 보다는 전체 맵 크기를 기준으로 어느 위치를 정해주는 것이 깔끔하겠죠?

나중에 맵 크기를 바꾸게 되었을 때에도 함수가 자동으로 위치를 계산해서 화면의 가운데에 출력할 수 있도록요.

 

위치값을 그냥 int x, int y로 만들어 쓰는 것 보다는 구조체를 만들면 훨씬 관리하기 편해지니까 

위치값을 저장하기 위한 구조체를 먼저 만듭시다. 

 

 

//in Mecro.h

struct Position {
	int x;
	int y;
};

 

이 구조체 또한 여러 곳에서 쓸 것이기 때문에 Mecro.h에서 만들어주세요. 

 

 

//in GameManager.h

private:
	Position m_CenterPosition;

 

GameManager.h에서 private으로 멤버변수를 하나 만듭니다. 

 

 

//in GameManager.cpp

GameManager::GameManager()
{
	m_MapSize.left = 0;
	m_MapSize.right = WIDTH;
	m_MapSize.top = 0;
	m_MapSize.bottom = HEIGHT;

	//특수문자는 2칸을 차지하기 때문에 특수문자를 이용해서 그리는 바둑판의 실제 너비는 원래 너비의 2배가 됨
        //그렇기 때문에 맵 상에서 센터위치는 너비와 같다고 볼 수 있다.
        m_CenterPosition.x = m_MapSize.right;
        //y는 세로 길이를 반으로 나눈 위치 
	m_CenterPosition.y = m_MapSize.bottom * 0.5f; //곱하기 연산이 나누기 연산보다 빠르다.
}

 

생성자에서 초기화하는 코드를 추가합니다. 

m_CenterPosition.y = m_MapSize.bottom * 0.5f; 에서 

m_CenterPosition.y = m_MapSize.bottom / 2; 라고 적어도 되지만

나누기 연산보다는 곱하기 연산이 훨씬 빠르기 때문에 곱하기 연산이 가능하다면 곱하기로 가는 것이 좋습니다. 

 

 

//in GameManager.cpp

int GameManager::MainMenu()
{
	int iSelect;
	m_DrawManager.DrawMidText("★ 오 목 ★", m_CenterPosition.x, m_CenterPosition.y * 0.5f);
	m_DrawManager.DrawMidText("1. 게임 시작", m_CenterPosition.x, m_CenterPosition.y * 0.7f);
	m_DrawManager.DrawMidText("2. 옵션 설정", m_CenterPosition.x, m_CenterPosition.y * 0.9f);
	m_DrawManager.DrawMidText("3. 게임 종료", m_CenterPosition.x, m_CenterPosition.y * 1.1f);
	m_DrawManager.BoxDraw(m_CenterPosition.x * 0.5f, m_CenterPosition.y * 1.3f, 10, 3);
	m_DrawManager.gotoxy(m_CenterPosition.x, m_CenterPosition.y * 1.4f);
	cin >> iSelect;

	return iSelect;
}

 

MainMenu 함수의 본문도 작성해줍니다. 

y값에 곱한 값들은 임의의 값을 넣어보고 실행해서 위치를 맞춰보는 식으로 하시면 적절한 값을 찾을 수 있습니다. 

 

 

//in GameManager.cpp

void GameManager::RunGame()
{
	m_DrawManager.GridDraw(0, 0, m_MapSize.right, m_MapSize.bottom);
	MainMenu();
}

 

그러면 저번에 만들었던 RunGame 함수에 메인 메뉴를 출력하는 함수를 추가해 봅시다. 

바둑판 그리는 함수를 먼저 호출한 다음 메인 메뉴 함수를 호출해 주세요. 

 

 

 

빌드해보면 위와 같은 모습을 볼 수 있습니다. 

잘 그려지죠?

 

근데 우리가 그린 타이틀 화면의 크기에 비해서 콘솔창이 많이 커 보여요. 

별로 아름답지 않으니까 콘솔창 크기를 타이틀 화면 크기에 맞춰줍시다!

 

 

//in GameManager.h

//다른 클래스에서 호출될 필요가 없기 때문에 private으로 선언 
private:
	void SetConsoleSize();

 

GameManager.h로 돌아와서 위와 같이 함수를 선언해주세요. 

다른 클래스에서 호출될 필요가 없는 함수는 private으로 선언하는 것이 훨씬 깔끔해보이고 불필요한 접근 가능성도 줄일 수 있습니다. 

 

 

//in GameManager.cpp

void GameManager::SetConsoleSize()
{
	char buf[256];
	int Width = (m_MapSize.right * 2) + 1; //여유공간+1
	int Height = m_MapSize.bottom + 6; //바둑판 아래에 메뉴를 출력할 공간+6
	sprintf(buf, "mode con: lines=%d cols=%d", Height, Width);
	system(buf);
}

 

cpp 파일로 가서 위와 같이 본문을 작성합니다. 

 

sprintf 함수는 printf 함수와 비슷하게 사용할 수 있는데요,

printf 함수가 " " 안에 쓴 string을 출력해주는 함수였다면

sprinft는 첫번째 인자로 받는 변수에 출력하고 싶은 string을 저장해주는 함수입니다. 

살다 보면 바로 출력하기 보다는 안 보이는 곳에서 단어 몇 개를 미리 조합 해 놓고 완성물을 한꺼번에 출력하고 싶을 때가 있잖아요?

그럴 때 유용하게 사용할 수 있는 함수입니다. 

 

그래서 string을 저장할 배열이 매개변수로 꼭! 필요합니다. 

 

 

//in GameManager.cpp

GameManager::GameManager()
{
	m_MapSize.left = 0;
	m_MapSize.right = WIDTH;
	m_MapSize.top = 0;
	m_MapSize.bottom = HEIGHT;

	//특수문자는 2칸을 차지하기 때문에 특수문자를 이용해서 그리는 바둑판의 실제 너비는 원래 너비의 2배가 됨
	//그렇기 때문에 맵 상의 센터위치는 너비와 같다고 볼 수 있다.
	m_CenterPosition.x = m_MapSize.right;
	m_CenterPosition.y = m_MapSize.bottom * 0.5f;

	SetConsoleSize();
}

 

마지막으로 맨 처음 GameManager 객체가 생성될 때 콘솔 크기도 세팅될 수 있도록 생성자에 함수를 추가해 주세요. 

여기까지 하시고 빌드해 보시면...

 

 

 

위와 같은 경고 메시지가 나오면서 빌드가 되지 않을 것입니다. 

내용에서 알 수 있듯이 sprintf는 보안에 취약해서 사용하지 않는 것을 권장한다고 합니다. 

그래서 이것을 해결하려면 sprintf 대신에 sprintf_s를 쓰거나, 

 

 

 

프로젝트명 위에서 마우스 우클릭을 합니다. 

 

 

 

위와 같이 메뉴가 나타납니다. 

맨 밑에 있는 속성을 클릭합니다. 

 

 

 

그러면 위와 같은 창을 볼 수 있는데

왼쪽에서 C/C++ 에 가서 SDL 검사를 아니요로 선택한 다음 확인을 누르시면 정상 빌드가 됩니다. 

 

 

 

SDL 검사를 끈 후 다시 빌드를 해 보시면 위와 같이 정상적으로 빌드되는 것을 보실 수 있습니다. 

콘솔 크기도 타이틀 화면에 알맞게 설정되었죠?

 


이번 시간엔 여기까지...

다음엔 메뉴를 선택하는 기능을 추가해 보겠습니다. 

그럼 예습복습 열심히 하시고 잊지말고 돌아와 주세요~~^^

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함