프로그래밍/Win32 API

##8. 비트맵 / 더블 버퍼링 / FSM / 스프라이트 / Scene 전환

hscho00 2020. 9. 15. 19:54

 

 

Bitmap

void CBitmap::Load_Bitmap(const TCHAR* _pFilename)
{
	HDC hDC = GetDC(g_hWnd);
	m_hMemDC = CreateCompatibleDC(hDC);
	ReleaseDC(g_hWnd, hDC);

	m_hBitmap = (HBITMAP)LoadImage(NULL, _pFilename, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

	m_hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap);
}

void CBitmap::Release()
{
	SelectObject(m_hMemDC, m_hOldBitmap);
	DeleteObject(m_hBitmap);
	DeleteDC(m_hMemDC);
}

더블 버퍼링(Double Buffering)

 

비트맵을 화면에 뿌려줄 때, 계속해서 그리는 작업을 반복하기 때문에 깜빡이는 현상이 나타남

이 현상을 해결하기 위해 더블버퍼링을 사용해야 함

매번 출력 내용을 화면에 바로 그리지 않고,

빈 비트맵 위에 출력해야 할 모든 비트맵을 그린 다음, 한번에 출력한다.

 

void CMainGame::Render()
{
	HDC HBackBuffer = g_BitmapMgr->FindOrNull(L"BackBuffer");

	g_SceneMgr->Render(HBackBuffer);

	BitBlt(m_hDC, 0, 0, WINWIDTH, WINHEIGHT, HBackBuffer, 0, 0, SRCCOPY);

	// ...
    
}

Finite State Machine (유한 상태 기계)

 

자신이 취할 수 있는 유한한 갯수의 상태들을 가진다.

그 중에서 반드시 하나의 상태만을 취한다.

현재 상태는 특정 조건이 되면 다른 상태로 변할 수 있다.


Sprite

// Struct.h
// ...
typedef struct tagFrame
{
	int	iFrameStart;
	int	iFrameEnd;
	int	iFrameScene;
	DWORD	dwFrameTime;
	DWORD	dwFrameSpeed;
} FRAME;

// Obj.cpp
// ...
void CObj::Frame_Move()
{
	if (m_tFrame.dwFrameTime + m_tFrame.dwFrameSpeed < GetTickCount())
	{
		++m_tFrame.iFrameStart;
		if (m_tFrame.iFrameStart > m_tFrame.iFrameEnd)
			m_tFrame.iFrameStart = 0;

		m_tFrame.dwFrameTime = GetTickCount();
	}
}

// Player.cpp
// ...
void CPlayer::ChangeState()
{
	if (m_ePreState != m_eCurState)
	{
		switch (m_eCurState)
		{
		case CPlayer::IDLE:
			m_tFrame.iFrameStart = 0;
			m_tFrame.iFrameEnd = 3;
			m_tFrame.iFrameScene = IDLE;
			m_tFrame.dwFrameTime = GetTickCount();
			m_tFrame.dwFrameSpeed = 200;
			break;
		case CPlayer::WALK:
			m_tFrame.iFrameStart = 0;
			m_tFrame.iFrameEnd = 5;
			m_tFrame.iFrameScene = WALK;
			m_tFrame.dwFrameTime = GetTickCount();
			m_tFrame.dwFrameSpeed = 100;
			break;
		case CPlayer::ATTACK:
        		// ...
			break;
		case CPlayer::HIT:
        		// ...
			break;
		case CPlayer::DEAD:
        		// ...
			break;
		}
		m_ePreState = m_eCurState;
	}
}

void CPlayer::Render(HDC _DC)
{
	// ...
    
	HDC hMemDC = CBmpMgr::Get_Instance()->Find_Image(m_pFrameKey);

	GdiTransparentBlt(_DC
		, m_tRect.left + iScrollX, m_tRect.top
		, m_tInfo.iCX, m_tInfo.iCY
		, hMemDC
		, m_tFrame.iFrameStart * 200, m_tFrame.iFrameScene * 200
		, 200, 200
		, RGB(0, 0, 0));
        
	// ...
}

SceneMgr

// SceneMgr.h

Class CScene;

class CSceneMgr
{
private:
	CSceneMgr();
	~CSceneMgr();

// 싱글톤
public:
	static CSceneMgr* GetInstance();
	static void DestroyInstance();

// 가질 수 있는 상태
public:
	enum SCENEID { SCENE_LOGO, SCENE_TITLE, SCENE_STAGE_1, SCENE_ENDING, SCENE_END };

	void ChangeScene(SCENEID _eScene);
    
// MainGame에서 호출할 함수
public:
	void Update();
	void LateUpdate();
	void Render(HDC _DC);

	CScene* Get_Scene() { return m_pScene; }

private:
	void Release();

private:
	static CSceneMgr* m_pInstance;

	CScene*		m_pScene;
	SCENEID		m_ePreScene;	// 현재 상태
	SCENEID		m_eCurScene;	// 변할 상태

};

#define g_SceneMgr CSceneMgr::GetInstance()