KoreanFoodie's Study
윈도우 API 프로그래밍 7 : 게임 프레임워크 구성 본문
윈도우 API 프로그래밍 7 : 게임 프레임워크 구성
지금은 간단한 게임이니까 WindowsProject1.cpp라는 단일 파일에 모든 기능을 구현했지만, 프로그램이 복잡해지면 사실 필요한 코드를 필요한 파일에 분할해서 구성해야 한다. 이 글에서는 이를 위한 밑작업을 어떻게 하는지를 다루고자 한다.
GameNode : 먼저 스켈레톤 클래스를 만들자
#pragma once
class GameNode
{
public:
GameNode();
~GameNode();
virtual void Init() = 0; // 순수 가상 함수
virtual void Update() = 0;
virtual void Render() = 0;
};
먼저 가장 기본적으로 Init, Update, Render라는 가상 메소드를 가진 클래스를 생성한다(위의 파일은 GameNode.h임). 가상 메소드는 알다시피 실제 객체의 구현을 따라가는 메소드이며, ' = 0' 을 붙여주게 되면 순수 가상 함수로, 이를 상속하는 클래스가 반드시 실제 기능을 구현할 의무를 가진다. 물론 순수 가상 함수가 선언된 클래스는 추상 클래스로 취급하게 된다.
MainNode : 실제로 우리가 구현할 녀석
#pragma once
#include "GameNode.h"
class MainGame : public GameNode
{
private:
struct tagBox
{
RECT rt;
float speed;
};
private:
POINT m_ptPos1; // 조작할 렉트의 좌표 값
RECT m_rtBox1; // 조작하는 렉트 정보
float m_fMoveSpeed;
int m_nScore;
int m_nLevel;
POINT m_ptMouse_prev;
bool m_isPicked;
vector<tagBox> m_vecBox; // 떨어지는 렉트의 정보
int m_nDelay;
public:
MainGame();
~MainGame();
virtual void Init() override;
virtual void Update() override;
virtual void Render() override;
};
(위의 파일은 GameNode.h) 거창하게 이야기 했지만, 사실 새롭게 짤 부분은 거의 없고, 기존에 WindowsProject1.cpp 파일에 있던 변수들이나 타입 정의들은 GameNode.h로, 실제 구현부에 해당하는 부분은 GameNode.cpp로 옮기면 된다.
여기서는 기존 전역 변수와 차별성을 두기 위해 "m_"을 붙여 멤버 변수임을 명시했다.
MainNode.cpp : 알맞은 메소드에 알맞은 코드를 옮기기
#include "framework.h"
#include "MainGame.h"
MainGame::MainGame()
{
}
MainGame::~MainGame()
{
}
void MainGame::Init()
{
m_ptPos1 = { WINSIZEX / 2, WINSIZEY - 30 }; // 조작할 렉트의 좌표 값
m_fMoveSpeed = 20;
m_nScore = 0;
m_nLevel = 0;
m_isPicked = false;
m_nDelay = 50;
}
void MainGame::Update()
{
InvalidateRect(g_hWnd, NULL, true); // 전체 영역을 다시 그린다. NULL이 들어가면 전체 화면.
// 0x0001
if (GetAsyncKeyState(VK_LEFT) & 0x8000 || GetAsyncKeyState('A') & 0x8000) {
if (m_rtBox1.left >= m_fMoveSpeed)
m_ptPos1.x -= m_fMoveSpeed;
else m_ptPos1.x = WINSIZEX;
}
else if (GetAsyncKeyState(VK_RIGHT) & 0x8000 || GetAsyncKeyState('D') & 0x8000) {
if (m_rtBox1.right <= WINSIZEX - m_fMoveSpeed)
m_ptPos1.x += m_fMoveSpeed;
else m_ptPos1.x = 0;
}
m_nLevel = (m_nScore > 0) ? (m_nScore / 100 + 1) : 1;
// 포지션 위치에 따른 렉트 정보 업데이트
m_rtBox1 = RECT_MAKE(m_ptPos1.x, m_ptPos1.y, 50);
if (m_nDelay >= 50) {
RECT rt;
tagBox box;
box.rt.left = rand() % (WINSIZEX - 30);
box.rt.right = box.rt.left + 30;
box.rt.top = -30;
box.rt.bottom = 0;
box.speed = rand() % 11 + 5;
m_vecBox.push_back(box);
m_nDelay = rand() % 20 + 30;
}
else m_nDelay += m_nLevel;
vector<tagBox>::iterator iter;
for (iter = m_vecBox.begin(); iter != m_vecBox.end(); iter++) {
iter->rt.top += iter->speed;
iter->rt.bottom += iter->speed;
RECT rt;
RECT rtIter = iter->rt;
if (iter->rt.top > WINSIZEY) {
m_nScore++;
m_vecBox.erase(iter);
break;
}
else if (IntersectRect(&rt, &m_rtBox1, &rtIter)) {
m_nScore -= 10;
m_vecBox.erase(iter);
break;
}
}
}
void MainGame::Render()
{
PAINTSTRUCT ps;
// HDC : Device Context Handle : 출력을 위한 모든 데이터를 가지는 구조체
HDC hdc = BeginPaint(g_hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
/*wstring wstr = L"코딩 지옥으로 입장을 허가합니다!!!";
TextOut(hdc, 10, 10, wstr.c_str(), wstr.length());*/
int roomSize = WINSIZEY / 9;
RECT_DRAW(m_rtBox1);
for (auto& elem : m_vecBox) {
RECT_DRAW(elem.rt);
}
char szBuf[32];
_itoa_s(m_nLevel, szBuf, 10, 10); // 정수값을 문자열 값으로 변환해주는 함수
string str = string(szBuf);
TextOutA(hdc, 10, 10, str.c_str(), str.length());
_itoa_s(m_nScore, szBuf, 10, 10); // 정수값을 문자열 값으로 변환해주는 함수
str = string(szBuf);
TextOutA(hdc, 10, 30, str.c_str(), str.length());
EndPaint(g_hWnd, &ps);
}
잘 보면 Init( )에서는 변수 초기화를, Update( )에서는 WM_TIMER에 해당하는 구현부를, Render( )에서는 WM_PAINT에 해당하는 코드를 가져온 것을 알 수 있다.
이제 WindowsProject1.cpp에서 GameNode 클래스에서 해당하는 함수를 call해주기만 하면 된다!
간단하게 바뀐 WindowsProject1.cpp
// 전역변수 부분
pMainGame = new MainGame; // 할당
pMainGame->Init();
// ... delete pMainGame을 나중에 반드시 해 주어야 한다! 기본 Message Loop 이후에.
case WM_TIMER: // 타이머에 의해서 호출
if (pMainGame)
pMainGame->Update();
break;
case WM_PAINT:
if (pMainGame)
pMainGame->Render();
break;
살펴보면 MainGame 포인터를 할당한 후, WM_TIMER와 WM_PAINT 블록에서 해당하는 클래스 메소드를 호출한 것으로 코드가 정리된 것을 확인할 수 있다.
더 자세한 내용이 궁금하시다면 직접 들어보시는 걸 추천드립니다!
'Game Dev > 윈도우 API' 카테고리의 다른 글
윈도우 API 프로그래밍 9 : 키매니저(키 입력 받기), bitset 예제 (0) | 2021.10.17 |
---|---|
윈도우 API 프로그래밍 8 : 객체 지향적인 윈도우 API 프로그래밍 (0) | 2021.10.15 |
윈도우 API 프로그래밍 6 : 간단한 UI 구현과 똥피하기 게임 예제 (0) | 2021.10.15 |
윈도우 API 프로그래밍 5 : 물체 떨어뜨리기 (간단한 똥피하기 게임 예제) (0) | 2021.10.15 |
윈도우 API 프로그래밍 4 : 충돌 검사 (IntersectRect...) (0) | 2021.10.15 |