김주현·2021년 8월 2일
0

Win API

목록 보기
6/14

씬을 구현 하고 씬을 통해 화면을 변경하고 구성해보겠습니다.

우선 부모 클래스로 사용할 씬을 생성해줍니다.

-Scene.cpp-

#include "stdafx.h"
#include "Scene.h"


CScene::CScene()
{
}


CScene::~CScene()
{
}
-Scene.h


#pragma once
class CScene abstract
{
public:
	explicit CScene();
	virtual ~CScene();

public:
	virtual int Ready_Scene() =0;
	virtual void Update_Scene() = 0; 
	virtual void Render_Scene(HDC hDC) =0; 
	virtual void Release_Scene() = 0;
};

게임 오브젝트와 같이 생성될 씬들의 부모로 사용할 클래스입니다 순수 가상함수들을 구성해놓습니다.

씬 매니저

게임 오브젝트와 같이 게임에 사용될 다양한씬들을 용도에따라 변경해줄수있는 매니저가 필요합니다 이를 씬매니저를 통해 구현하겠습니다.

-Scene_Manager.cpp-

#include "stdafx.h"
#include "Scene_Manager.h"
#include "Loading.h"
#include "Stage.h"
#include "MyMenu.h"

//스택틱 변수를 널포인터로 초기화해줍니다.
CScene_Manager* CScene_Manager::m_pInstance = nullptr; 


CScene_Manager::CScene_Manager()
//이니셜라이저를 통해 멤버 변수들을 초기화해줍니다.
	:m_eCurScene(SCENE_END)
	, m_eNextScene(SCENE_END)
	, m_pScene(nullptr)
{
}


CScene_Manager::~CScene_Manager()
{
	Release_Scene_Manager(); 
}

void CScene_Manager::Scene_Change(ID eNextID)
{
	//FSM 유한 상태 기계 
	m_eNextScene = eNextID; 
	// 이경우는 어떤 경우 ? 즉 씬이 변경되야 하는 상황.
    
    	// 현재씬과 다음씬(들어온값)이 다른경우에만 씬을 교체해주어야합니다
        // 같은 값이 들어온다면 유지해주고 교체해주지않습니다.
        
	if (m_eCurScene != m_eNextScene)
	{
    		//우선 씬을 교체해주기위해 현재 씬을 삭제해줍니다.
		Safe_Delete(m_pScene); 
       		//스위치문을통해 들어온값에 맞는 씬을 추가해줍니다.
		switch (m_eNextScene)
		{
		case CScene_Manager::SCENE_LOADING:
			m_pScene = CLoading::Create(); 
			break;
		case CScene_Manager::SCENE_STAGE:
			m_pScene = CStage::Create(); 
			break;

		case CScene_Manager::SCENE_MENU:
			m_pScene = CMyMenu::Create(); 
			break;
		default:
			break;
		}
        	//다음 같은값이 들어오면 씬을 교체하지않을것이기때문에 
            	//커렌트씬을 변경해줍니다.
		m_eCurScene = m_eNextScene; 
	}
}
//업데이트와 렌더 릴리즈입니다.
//메인앱에서 게임오브젝트를 타지않고 이제 메인엡에서 씬을 탄후
//게임오브젝트를 탑니다.
void CScene_Manager::Update_Scene_Manager()
{
	m_pScene->Update_Scene(); 
}

void CScene_Manager::Render_Scene_Manager(HDC hDC)
{
	m_pScene->Render_Scene(hDC); 
}

void CScene_Manager::Release_Scene_Manager()
{
	Safe_Delete(m_pScene); 
}
-Scene_Manager.h-

#pragma once
class CScene; 
class CScene_Manager final
{
public:
	//각 씬에 맞는 열거체를 만들어줍니다.
	enum ID {SCENE_LOADING, SCENE_MENU,SCENE_STAGE, SCENE_END};
public:
	//씬 매니저는 싱글톤을 이용해 구성합니다.
	static CScene_Manager* Get_Instance()
	{
		if (nullptr == m_pInstance)
			m_pInstance = new CScene_Manager; 
		return m_pInstance; 
	}
	static void Destroy_Instance()
	{
		if (m_pInstance)
		{
			delete m_pInstance; 
			m_pInstance = nullptr; 
		}
	}
private:
	static CScene_Manager* m_pInstance; 
private:
	CScene_Manager();
	~CScene_Manager();
public:
	void Scene_Change(ID eNextID); 
	void Update_Scene_Manager(); 
	void Render_Scene_Manager(HDC hDC); 
	void Release_Scene_Manager(); 
private:
	// m_pScene이 실질적으로 가지고있는 씬이고 cur,next로 씬을 변경할때
    	// 사용합니다.
	CScene* m_pScene; 
	ID m_eCurScene; 
	ID m_eNextScene; 

};

싱글톤으로 구현을해 필요에따라 씬을 교체해주고 나타낼수있습니다.

로딩

우선 게임의 가장 처음 나오는 씬인 로딩씬을 만들어 보겠습니다.

-Loading.cpp-

#include "stdafx.h"
#include "Loading.h"


CLoading::CLoading()
{
}


CLoading::~CLoading()
{
	Release_Scene(); 
}

int CLoading::Ready_Scene()
{
	return 0;
}

void CLoading::Update_Scene()
{
	if (CKey_Manager::Get_Instance()->Key_Up(KEY_RIGHT))
	{
		CScene_Manager::Get_Instance()->Scene_Change(CScene_Manager::SCENE_MENU);
	}
    //로딩은 초기화면 이기때문에 여기선 오른쪽키를 입력받으면 씬을 바꾸도록 했습니다.
    
}

void CLoading::Render_Scene(HDC hDC)
{
	HDC hMemDC = CBitmap_Manager::Get_Instance()->FindImage(L"Logo"); 
    //메인앱에서 미리 받아온 이미지를 가져와 화면에 그려줍니다.
	if (nullptr == hMemDC)
	{
		return; 
	}
	BitBlt(hDC, 0, 0, WINCX, WINCY, hMemDC, 0, 0, SRCCOPY); 
}

void CLoading::Release_Scene()
{
}

CScene* CLoading::Create()
{
	CScene* pInstance = new CLoading; 
	if (0 > pInstance->Ready_Scene())
		Safe_Delete(pInstance); 

	return pInstance;
}
-Loading.h-

#pragma once
#include "Scene.h"
class CLoading final:
	public CScene
{
private:
	explicit CLoading();
public:
	virtual ~CLoading();
public:
	// CScene을(를) 통해 상속됨
	virtual int Ready_Scene() override;
	virtual void Update_Scene() override;
	virtual void Render_Scene(HDC hDC) override;
	virtual void Release_Scene() override;
public:
	static CScene* Create(); 
};

로딩까지 구현했다면 MainCPP에서 기존의 게임구성요소들을 변경해주어야합니다.

이전에는 메인앱->게임오브젝트매니저->게임오브젝트순으로 흘러갔다면
이제는 메인앱->씬매니저->씬-게임오브젝트매니저->게임오브젝트 순으로 흘러가기때문입니다.

우선 기존 요소들은 씬의 스테이지 클래스를 만들어 옮겨준후

업데이트와 렌더부분도 게임오브젝트매니저가아닌 씬매니저를 통해 호출해줍니다 씬매니저의 씬이 해당하는 게임오브젝트매니저를 호출할것입니다.

-MainApp.cpp-


#include "stdafx.h"
#include "MainApp.h"
#include "Player.h"
#include "Monster.h"
#include "Collision_Manager.h"
#include "Mouse.h"
#include "GameObject_Manager.h"
#include "Line_Manager.h"
#include "Bitmap_Manager.h"
#include "Scene_Manager.h"
CMainApp::CMainApp()
	:m_iFPS(0)
	, m_szFPS(L"")
	, m_dwFPSTime(0)
	,m_hDC(nullptr)
{
}
/*
원래 구조 
Client -> MainApp -> 각각의 오브젝트들 Update, Render 수행. 
Client -> MainApp -> GameObject_Manager-> 각각의 오브젝트들 Update, Render 수행. 
client -> Mainapp -> Scene_Manager -> Scene -> GameObject_Manager - > 각각의 오브젝트들 Update, Render 수행
*/

CMainApp::~CMainApp()
{
	Release_MainApp(); 
}

int CMainApp::Ready_MainApp()
{
	m_hDC = GetDC(g_hWnd); 
	m_dwFPSTime = GetTickCount(); 



	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/BackBuffer.bmp", L"BackBuffer"); 

	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Back.bmp", L"DubleBuffer");
	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/maja2.bmp", L"maja2");
	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Logo/Logo.bmp", L"Logo");

	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Menu/Menu.bmp", L"Menu");
	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Button/Start.bmp", L"Start");
	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Button/Edit.bmp", L"Edit");
	CBitmap_Manager::Get_Instance()->Insert_Bitmap(L"../Image/Button/Exit.bmp", L"Exit");

	CScene_Manager::Get_Instance()->Scene_Change(CScene_Manager::SCENE_LOADING);

	return READY_OK; 
}

void CMainApp::Update_MainApp()
{
	CKey_Manager::Get_Instance()->Key_Update();
	CScene_Manager::Get_Instance()->Update_Scene_Manager();
}

void CMainApp::Render_MainApp()
{
// 	Rectangle(m_hDC, 0, 0, WINCX, WINCY); 
// 	Rectangle(m_hDC, 100, 100, WINCX - 100, WINCY - 100); 
	HDC hDubleBuffer = CBitmap_Manager::Get_Instance()->FindImage(L"DubleBuffer"); 

	HDC hMemDC = CBitmap_Manager::Get_Instance()->FindImage(L"BackBuffer"); 
	BitBlt(hDubleBuffer, 0, 0, WINCX, WINCY, hMemDC, 0, 0, SRCCOPY);

	CScene_Manager::Get_Instance()->Render_Scene_Manager(hDubleBuffer);

	++m_iFPS; 
	if (m_dwFPSTime + 1000 < GetTickCount())
	{
		swprintf_s(m_szFPS, L"FPS : %d", m_iFPS); 
		m_iFPS = 0; 
		m_dwFPSTime = GetTickCount(); 
	}
	TextOut(hDubleBuffer, 100, 100, m_szFPS, lstrlen(m_szFPS));

	BitBlt(m_hDC, 0, 0, WINCX, WINCY, hDubleBuffer, 0, 0, SRCCOPY); 
}

void CMainApp::Release_MainApp()
{
	ReleaseDC(g_hWnd, m_hDC); 
	CKey_Manager::Destroy_Instance(); 
	CBitmap_Manager::Destroy_Instance(); 
	CGameObject_Manager::Destroy_Instance(); 
	CLine_Manager::Destroy_Instance(); 
	CScene_Manager::Destroy_Instance();
}

메뉴

다음은 게임 메뉴버튼을 띄울 메뉴버튼을 만들어보겠습니다.

우선 로딩에서 오른쪽키를 입력받으면 메뉴로 넘어가게 구성해두었기때문에 바로 메뉴 클래스를 만들어 보겠습니다.

버튼

메뉴에 올려놓을 버튼을 게임오브젝트를 상속받아서 구현하겠습니다.

-MyButton.h-

#pragma once
#include "GameObject.h"
class CMyButton final:
	public CGameObject
{
private:
	explicit CMyButton();
public:
	virtual ~CMyButton();
public:
	void Set_FrameKey(const TCHAR* pFrameKey) { m_pFrameKey = pFrameKey;  }
public:
	// CGameObject을(를) 통해 상속됨
	virtual int Ready_GameObject() override;
	virtual int Update_GameObject() override;
	virtual void Late_Update_GameObject() override;
	virtual void Render_GameObject(HDC hDC) override;
	virtual void Release_GameObject() override;
public:
	static CGameObject * Create();

private:
	const TCHAR* m_pFrameKey; //프레임키를 통해 이미지를 불러옵니다
	int m_iDrawID; //ID를통해 그림을 어디서부터 읽어올지 결정합니다
};
-MyButton.cpp-

#include "stdafx.h"
#include "MyButton.h"


CMyButton::CMyButton()
	:m_iDrawID(0)
{
}


CMyButton::~CMyButton()
{
}

int CMyButton::Ready_GameObject()
{
	m_tInfo.iCX = 150; 
	m_tInfo.iCY = 150; 
    //버튼 이미지의 맞춰 크기를 설정해줍니다.

	return READY_OK;
}

int CMyButton::Update_GameObject()
{
	CGameObject::Update_Rect_GameObject();
	POINT pt{}; 
	//커서의 위치를 가져온뒤 좌표를 화면에 맞게 해주고
    //PtInRect를통해 만약 마우스와 충돌하면m_iDrawID = 1로
    //이미지를 바꿔줍니다.
	GetCursorPos(&pt); 
	ScreenToClient(g_hWnd, &pt); 
	if (PtInRect(&m_tRect, pt))
	{

		m_iDrawID = 1; 
	}
	else m_iDrawID = 0; 
	return 0;
}

void CMyButton::Late_Update_GameObject()
{
}

void CMyButton::Render_GameObject(HDC hDC)
{
	CGameObject::Update_Rect_GameObject();
	HDC hMemDC = CBitmap_Manager::Get_Instance()->FindImage(m_pFrameKey);
	if (nullptr == hMemDC)
		return; 

	GdiTransparentBlt(hDC,
		m_tRect.left,
		m_tRect.top,
		m_tInfo.iCX,
		m_tInfo.iCY, 
		hMemDC,
		m_tInfo.iCX * m_iDrawID, 0, //X축의 위치를 ID에따라 다르게 그려줍니다.
		m_tInfo.iCX, m_tInfo.iCY,
		RGB(255, 255, 255));
}

void CMyButton::Release_GameObject()
{
}
CGameObject * CMyButton::Create()
{
	CGameObject* pInstance = new CMyButton;
	if (0 > pInstance->Ready_GameObject())
		Safe_Delete(pInstance);

	return pInstance;
}

이런식으로 메인로고가 나오고 키를입력받으면 다음화면으로 넘어가게 구성해주었습니다

0개의 댓글

Powered by GraphCDN, the GraphQL CDN