Win32API Scene Manager(1)
https://www.youtube.com/watch?v=_IeoFRrYPiY&list=PL4SIC1d_ab-ZLg4TvAO5R4nqlJTyJXsPK&index=15
< 배운 내용 정리 >
화면에 존재하는 모든 물체는 Object
오브젝트를 종류별로 나누기 위해 enum class를 사용해서 define 하기
enum class GROUP_TYPE
{
DEFAULT,
PLAYER,
MISSILE,
MONSTER,
END = 32,
};
Object들을 관리해주는 구조가 필요 -> Scene 필요
Scene도 stage와 같이 여러가지로 나뉨 ( 상속되면서 파생 )
모든 Scene들이 공통적으로 가져야 될 사항은?
( Scene는 추후에 여러가지로 나뉘는 부모 클래스( 상속을 시킬 목적 )이기 때문에 소멸자에 가상함수 무조건 해주기, 상속할땐 무조건 사용하기 )
#pragma once
//전방선언 ( 실제 타입에 대한 구체적인 정보 X , 포인터 타입으로 밖에 사용 불가능 )
class CObject;
class CScene
{
private:
vector<CObject*> m_arrObj[(UINT)GROUP_TYPE::END]; // 오브젝트를 저장 및 관리할 벡터를 그룹 개수 만큼 선언
wstring m_strName; // Scene 이름
public:
void SetName(const wstring& _strName) { m_strName = _strName; }
const wstring& GetName() { return m_strName; }
public:
CScene();
virtual ~CScene();
};
Scene도 종류별로 나누기 위해 enum class를 사용해서 define 하기
enum class SCENE_TYPE
{
TOOL,
START,
STAGE_01,
STAGE_02,
END,
};
Scene들을 관리해줄 Manager도 필요함 ex ) start scene이구나, game scene 같은
// CSceneMgr.h
#pragma once
class CScene;
class CSceneMgr
{
SINGLE(CSceneMgr);
private:
CScene* m_arrScene[(UINT)SCENE_TYPE::END]; // 모든 Scene 목록
CScene* m_pCurScene; // 현재 Scene
public:
void init();
};
// CSceneMgr.cpp
#include "pch.h"
#include "CSceneMgr.h"
#include "CScene_Start.h"
CSceneMgr::CSceneMgr()
: m_arrScene{}
, m_pCurScene(nullptr)
{
}
CSceneMgr::~CSceneMgr()
{
// 씬 전부 삭제
for (UINT i = 0; i < (UINT)SCENE_TYPE::END; ++i)
{
if (nullptr != m_arrScene[i])
{
delete m_arrScene[i];
}
}
}
void CSceneMgr::init()
{
// Scene 생성
m_arrScene[(UINT)SCENE_TYPE::START] = new CScene_Start;
// m_arrScene[(UINT)SCENE_TYPE::TOOL] = new CScene_Tool;
// m_arrScene[(UINT)SCENE_TYPE::STAGE_01] = new CScene_Stage01;
// m_arrScene[(UINT)SCENE_TYPE::STAGE_02] = new CScene_Stage02;
// 현재 씬 지정
m_pCurScene = m_arrScene[(UINT)SCENE_TYPE::START];
}
CScene_Start 는 Scene의 한 종류, 이곳에서 오브젝트들을 추가할 예정임
// CScene_Start.h
#pragma once
#include "CScene.h"
class CScene_Start :
public CScene
{
public:
CScene_Start();
~CScene_Start();
};
Win32API Scene Manager (2)
https://www.youtube.com/watch?v=A9eL3p0MfLA&list=PL4SIC1d_ab-ZLg4TvAO5R4nqlJTyJXsPK&index=16
< 배운 내용 정리 >
부모쪽에서 가상함수 시켜서 부모 포인터로 Enter 함수 호출될수 있게 함
그러나 부모쪽에서는 구현할 필요가 없기 때문에 interface
Scene을 상속받아가는 모든 파생되는 클래스들은 Enter 를 자기 버전으로 구현을 해야함 -> 순수 가상 함수
// CScene.h
#pragma once
//전방선언 ( 실제 타입에 대한 구체적인 정보 X , 포인터 타입으로 밖에 사용 불가능 )
class CObject;
class CScene
{
private:
vector<CObject*> m_arrObj[(UINT)GROUP_TYPE::END]; // 오브젝트를 저장 및 관리할 벡터를 그룹 개수 만큼 선언
wstring m_strName; // Scene 이름
public:
void SetName(const wstring& _strName) { m_strName = _strName; }
const wstring& GetName() { return m_strName; }
void update();
void render(HDC _dc);
virtual void Enter() = 0; // 해당 Scene에 진입 시 호출
virtual void Exit() = 0; // 해당 Scene을 탈출 시 호출
protected:
void AddObject(CObject* _pObj, GROUP_TYPE _eType)
{
m_arrObj[(UINT)_eType].push_back(_pObj);
}
public:
CScene();
virtual ~CScene();
};
CScene_Start 클래스는 CScene을 상속받으므로 Enter함수와 Exit를 구현해야함
#include "pch.h"
#include "CScene_Start.h"
#include "CObject.h"
CScene_Start::CScene_Start()
{
}
CScene_Start::~CScene_Start()
{
}
void CScene_Start::Enter()
{
// Object 추가
CObject* pObj = new CObject;
pObj->SetPos(Vec2(640.f, 384.f));
pObj->SetScale(Vec2(100.f, 100.f));
AddObject(pObj, GROUP_TYPE::DEFAULT);
}
void CScene_Start::Exit()
{
}
이때 Enter 함수에서 Object를 추가하고, 위치 크기 등을 지정 해 준다
그리고 부모 클래스의 m_arrObj에 새로만든 Object 객체를 추가한다
그런데 자식 클래스에서 m_arrObj를 접근 할수 없다
자식클래스가 부모 클래스의 private 멤버변수를 접근하기 위해서 부모의 멤버변수 private를 protected로 변경하는 법은
디버깅할때 좋지 않은 방법이다 ( 멤버변수는 보통 protected 나 public으로 사용하지 말아야한다 )
-> 이러한 문제를 해결하는 방법은 private 멤버변수를 접근, 수정 하는 함수를 protected로 만들어서 해결 할 수 있다
protected:
void AddObject(CObject* _pObj, GROUP_TYPE _eType)
{
m_arrObj[(UINT)_eType].push_back(_pObj);
}
이후 자식에서 new로 만든 동적할당 객체들은 부모 벡터 멤버 변수에서 모두 관리중이니 사라질때는 부모 클래스에서 delete 하기
(상속 사용 하는 이유 : 코드 재사용)
CScene::~CScene()
{
for (UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i)
{
for (size_t j = 0; j < m_arrObj[i].size(); ++j) // 벡터니까
{
// m_arrObj[i] 그룹벡터의 j 물체 삭제
delete m_arrObj[i][j];
}
}
}
< update 흐름 >
objecct에서 KeyMgr를 통해 키입력을 받고 Object를 이동
< render 흐름 >
Core에서 SceneMgr에게 render 지시 ->
SceneMgr에서는 현재 Scene에게 render 하라고 지시 ->
현재 Scene은 모든 Object에게 render하라고 지시
이런 흐름을 통해 Core에서는 코드가 간단해지고 각자 클래스들이 맡은 역할들을 수행하게 됨
// CCore.cpp
void CCore::progress() // 프로그램이 도는 곳
{
// Manager Update
CTimeMgr::GetInst()->update();
CKeyMgr::GetInst()->update();
CSceneMgr::GetInst()->update();
// =============
// Rendering
// =============
// 화면 청소
// -1인 이유 (테투리선이 보이니까)
Rectangle(m_memDC, -1, -1, m_ptResolution.x + 1, m_ptResolution.y + 1);
CSceneMgr::GetInst()->render(m_memDC);
// 비트맵을 복사
BitBlt(m_hDC, 0, 0, m_ptResolution.x, m_ptResolution.y, m_memDC, 0, 0, SRCCOPY);
}
// CSceneMgr.cpp
#include "pch.h"
#include "CSceneMgr.h"
#include "CScene_Start.h"
CSceneMgr::CSceneMgr()
: m_arrScene{}
, m_pCurScene(nullptr)
{
}
CSceneMgr::~CSceneMgr()
{
// 씬 전부 삭제
for (UINT i = 0; i < (UINT)SCENE_TYPE::END; ++i)
{
if (nullptr != m_arrScene[i])
{
delete m_arrScene[i];
}
}
}
void CSceneMgr::init()
{
// Scene 생성
m_arrScene[(UINT)SCENE_TYPE::START] = new CScene_Start;
m_arrScene[(UINT)SCENE_TYPE::START]->SetName(L"Start Scene");
// m_arrScene[(UINT)SCENE_TYPE::TOOL] = new CScene_Tool;
// m_arrScene[(UINT)SCENE_TYPE::STAGE_01] = new CScene_Stage01;
// m_arrScene[(UINT)SCENE_TYPE::STAGE_02] = new CScene_Stage02;
// 현재 씬 지정
m_pCurScene = m_arrScene[(UINT)SCENE_TYPE::START];
m_pCurScene->Enter();
}
void CSceneMgr::update()
{
m_pCurScene->update();
}
void CSceneMgr::render(HDC _dc)
{
m_pCurScene->render(_dc);
}
// CScene.cpp
#include "pch.h"
#include "CScene.h"
#include "CObject.h"
CScene::CScene()
{
}
CScene::~CScene()
{
for (UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i)
{
for (size_t j = 0; j < m_arrObj[i].size(); ++j) // 벡터니까
{
// m_arrObj[i] 그룹벡터의 j 물체 삭제
delete m_arrObj[i][j];
}
}
}
void CScene::update()
{
for (UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i)
{
for (size_t j = 0; j < m_arrObj[i].size(); ++j)
{
m_arrObj[i][j]->update();
}
}
}
void CScene::render(HDC _dc)
{
for (UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i)
{
for (size_t j = 0; j < m_arrObj[i].size(); ++j)
{
m_arrObj[i][j]->render(_dc);
}
}
}
// CObject.cpp
#include "pch.h"
#include "CObject.h"
#include "CKeyMgr.h"
#include "CTimeMgr.h"
CObject::CObject()
: m_vPos{}
, m_vScale{}
{
}
CObject::~CObject()
{
}
void CObject::update()
{
if (CKeyMgr::GetInst()->GetKeyState(KEY::W) == KEY_STATE::HOLD)
{
m_vPos.y -= 200.f * fDT;
}
if (CKeyMgr::GetInst()->GetKeyState(KEY::S) == KEY_STATE::HOLD)
{
m_vPos.y += 200.f * fDT;
}
if (CKeyMgr::GetInst()->GetKeyState(KEY::A) == KEY_STATE::HOLD)
{
m_vPos.x -= 200.f * fDT;
}
if (CKeyMgr::GetInst()->GetKeyState(KEY::D) == KEY_STATE::HOLD)
{
m_vPos.x += 200.f * fDT;
}
}
void CObject::render(HDC _dc)
{
Rectangle(_dc, (int)(m_vPos.x - m_vScale.x / 2.f), (int)(m_vPos.y - m_vScale.y / 2.f)
, (int)(m_vPos.x + m_vScale.x / 2.f), (int)(m_vPos.y + m_vScale.y / 2.f));
}
여기까지가 게임 프로그램의 가장 기본적인 framework 구조임 ( 가장 간단한 base 구조, 이 구조에서 큰 흐름은 바뀌지 않는다 )
'Win32API' 카테고리의 다른 글
Win32API 기초 수학 (1) | 2025.01.14 |
---|---|
Win32API Object (0) | 2025.01.14 |
Win32API Key Manager (0) | 2025.01.14 |
Win32API Double Buffering (1) | 2025.01.14 |
Win32API Timer (0) | 2025.01.14 |