API 구조에서 메시지 처리부분 Peekmessage 부분에서
if문으로 MainGame의 Init 함수를 불러 MainGame 클래스를 초기화 해주고,
Progress 함수에서 처리를 하고, Progress 함수 끝에서 Render 함수를 호출하여, 화면에 뿌려준다.
게임의 기본 구조는 Init로 초기화 해주고, Progress로 처리하고, Render로 Progress로 처리한걸 그려주는 방식으로 하는게
구조적으로 좋다.
MainGame 클래스 예제
//------------------------------------ MainGame.h ------------------------------------ //
#pragma once // 중복 include를 제거 하기 위해 쓴다.
#include "Defines.h" // include 파일들을 모아 놓은 헤더 파일
// 헤더 파일의 순서로 인한 헤더 참조가 꼬일 수 있으니 주의!!!!
#include "Value.h" // typedef한 변수 타입이나 enum문등 여러 클래스에서 같이 쓰이는것을 모아 놓은 헤더파일
class CMainGame
{
private:
HDC m_hdc; // 윈도우 화면 안에 쓰이는 선이나 도형 색상등의 정보가 들어 있는 것이다.
CObj* m_pPlayer; // Obj란 부모 클래스에서 다형성을 이용하여 자식 클래스에게 상속을 내려줘서 하기 위해
// 이와 같이 객체를 선언.
list<CObj*> m_MonsterList; // Obj 클래스에는 기본 Init, Progress, Render 함수를 가상함수화 해서 자식에서 사용
list<CObj*> m_BulletList[BI_END]; // 다시 사용하게 해주고, 자식들은 Obj 클래스에서 상속을 받으므로 상속을 받은
// 클래스 등은 서로 충돌 체크 및 서로의 거리 등의 체크가 쉽게 할 수 있다.
// BulletList는 몬스터 총알과 플레이어 총알을 구분해서 체크 하기 위해 enum을
// 이용하여 리스트를 생성 하였다.
// enum문은 value.h 파일에 다음과 같이 선언 되어 있다.
// enum BULLETID {BI_PLAYER, BI_MONSTER, BI_END};
// 플레이어 ID와 몬스터 ID, 그리고 총알의 끝을 알려 주는 BI_END를 만들어서 리스트에서 push_back 할 때,
// iter로 for문을 돌려서 생성 할 때, 총알 리스트 갯수를 BI_END로 갯수 처리도 가능하다.
public:
bool Init(void);
void Progress(void);
void Render(void);
public:
CMainGame(void);
~CMainGame(void);
};
//------------------------------------MainGame.cpp------------------------------------//
#include "StdAfx.h"
#include "MainGame.h"
CMainGame::CMainGame(void)
: m_pPlayer(NULL) // Obj 클래스의 주소로 선언한 m_pPlayer 포인터 변수를 NULL로 초기화
// 헤더 파일 참조.
{
}
CMainGame::~CMainGame(void)
{
list<CObj*>::iterator iter;
ReleaseDC(g_hWnd, m_hdc); // API 메인 함수에서 전역으로 선언했던 g_hWnd핸들 값의 HDC 값을 리턴하는 함수
delete m_pPlayer;
for(iter = m_MonsterList.begin(); iter != m_MonsterList.end(); ++iter)
{
delete *iter; // 몬스터 객체의 포인터로 객체 삭제
*iter = NULL; // 포인터 주소값을 NULL로 대입 . 이렇게 해야 객체가 재 참조 될 때 쓰레기 값이
} // 않 들어가므로 체크가 가능 해진다.
m_MonsterList.clear(); // 리스트에 저장되어 있는 객체의 주소의 이름 삭제
}
bool CMainGame::Init(void)
{
list<CObj*>::iterator iter; // 몬스터 객체의 주소값을 가지고 있는 리스트를 만들기 위해서 리스트의 주소값인
// iter 선언
m_hdc = GetDC(g_hWnd); // API 메인 함수에서 전역으로 선언했던 g_hWnd핸들 값의 HDC 값을 받아오는 함수
// GetDC 함수를 사용하면 객체 소멸시 반드시 ReleaseDC 함수로 HDC값을 반환해야함.
m_pPlayer = CObjFactory<CPlayer>::CreateObj();
//플레이어한테 총알 정보와 몬스터 정보를 보냄(Set함수들은 Cplayer클래스에 있음.)
((CPlayer*)m_pPlayer)->SetBulletList(&m_BulletList[BI_PLAYER]);
((CPlayer*)m_pPlayer)->SetMonsterList(&m_MonsterList);
for(_INT i = 0; i < 3; ++i)
{
m_MonsterList.push_back(CObjFactory<CMonster>::CreateObj());
iter = m_MonsterList.end();
--iter; // iter의 끝을 잡아주고 감소 연산자를 사용하여 방금 생성한
// 객체의 주소값으로 함수들이 접근이 가능해진다.
((CMonster*)*iter)->SetPos(600, i * 100 + 100); // SetPos 함수는 몬스터 클래스에서 몬스터의 중심점 x,y좌표를
// 대입해주는 녀석이다.
((CMonster*)*iter)->SetBulletList(&m_BulletList[BI_MONSTER]);
}
return true;
}
// Peekmessage에서 처리 해줄때, GetTickCount()로 시간값을 받아 줄때 +10을 해줘서 0.01초 마다 불러지는 함수다.)
void CMainGame::Progress(void)
{
list<CObj*>::iterator iter;
m_pPlayer->Progress();
for(iter = m_MonsterList.begin(); iter != m_MonsterList.end(); ++iter)
{
(*iter)->Progress();
}
for(_INT i = 0; i < BI_END; ++i) // enum 값으로 0이면 플레이어 1이면 몬스터 2면 총갯수를 사용해서 enum문의 2중 활용
{
for(iter = m_BulletList[i].begin(); iter != m_BulletList[i].end(); ++iter)
{
(*iter)->Progress();
}
}
Render();
}
void CMainGame::Render(void)
{
list<CObj*>::iterator iter;
list<CObj*>::iterator iter1;
TCHAR szBuf[128] = {0}; // 화면에 글씨 출력을 위한 char 변수 초기화.
// WINSIZEX, WINSIZEY는 상수로 윈도우 사이즈의 가로, 세로 값을 넣었다.
Rectangle(m_hdc, 0, 0, WINSIZEX, WINSIZEY); // fake로 화면에 사각형을 그려 다른 객체들의 잔상을 않보여준다.
// 케릭터등이 움직 일때 기존것을 삭제 않해주고 계속 그려주므로
// 이것을 선언하지 않으면, 플레이어등이 이동하면 플레이어등이
// 주루룩 그려진다.
m_pPlayer->Render(m_hdc); // api에서 화면을 그릴 때 하는 HDC 값을 다른 클래스에 넘겨줘서
// 다른 클래스에 객체등을 그리게 해준다.
// HDC은 도형을 그릴때 테두리색이나 글자를 출력 할 때,
// 글자색등의 정보를 가지고 있다.
for(iter = m_MonsterList.begin(); iter != m_MonsterList.end(); ++iter)
{
(*iter)->Render(m_hdc);
}
for(_INT i = 0; i < BI_END; ++i)
{
for(iter = m_BulletList[i].begin(); iter != m_BulletList[i].end(); ++iter)
{
(*iter)->Render(m_hdc);
}
}
}