Win32API Scene Manager ( 기본 framework )

 

 

 

< 배운 내용 정리 >

 

화면에 존재하는 모든 물체는 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();
};

 

 
 

 

< 배운 내용 정리 >

 

부모쪽에서 가상함수 시켜서 부모 포인터로 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
  Comments