https://hyrule.tistory.com/111
*** 공부 방법 ***
1. 코딩을 해야 하는 부분은 첫 부분에 변수나 함수, 메소드에 대한 선언이 코드블럭으로 표시되어 있다. //ex) MakeFunction(); 2. 코드블럭 하단에는 해당 선언에 대한 구현 로직이 작성되어 있다. (ex)
hyrule.tistory.com
지난 1번 글에서, 게임은 왜 GetMessage를 안 쓰고 PeekMessage를 사용하는지 설명했었다.
https://hyrule.tistory.com/109
01. 프레임워크에 사용될 WINAPI32 기본 생성 코드 알아보기
[WIN32API] 어렵게 생각할 필요 없이, Windows에서 제공하는 함수의 집합이다. 예를 들어 우리가 게임을 돌리고 있을 때 절전모드에 진입하는걸 막는다던지 하는 것들을 조정하도록 해 주는 것이다. W
hyrule.tistory.com
이번 글에서는 일단 만들어두기만 했던 메시지 처리 부분을 수정한다.
PeekMessage()
GetMessage() 함수가 받던 4개의 인자는 동일하다. 거기에 추가로 한 개의 인자를 더 받는다.
- 5번 인자: 메시지큐로부터 꺼내온 메시지를 메시지큐에서 지울지 말지 여부
- 받은 메시지(게임이므로 입력)는 지워준다: PM_REMOVE 를 인자로 전달한다.
- GetMessage()함수와의 차이점
- GetMessage() 함수는 메시지큐가 비어있을 경우 메시지가 들어올 때까지 함수 안에서 대기한다.
- 하지만 PeekMessage() 함수는 메시지큐가 비어있으면 'false'를 반환하며 함수를 빠져나온다.
- 메시지큐가 비어있으면 false를 반환한다는 점에서 착안
- if문을 사용: 메시지큐가 비어있을 때 else 문으로 들어가서 게임 로직을 동작시키면 된다.
CGameManager::Logic()
게임로직이 들어갈 함수.
PeekMessage가 false일 때, 이 함수로 들어가서 입력을 받고, 프레임을 렌더링하는 등의 일을 한다.
아래의 함수들은 모두 이 함수 안에 들어간다.
- cf)게임의 흐름을 구성하는 단계
- 사용자의 입력
- 입력받은 내용에 대해서 데이터 업데이트 + 인공지능의 데이터 업데이트
- 업데이트된 데이터를 토대로 충돌을 수행
- 출력이 되어야 하는 물체들을 판단
- 화면에 출력이 되어야 하는 물체들을 출력
CGameManager::Input(float DeltaTime)
- 입력을 처리해 주는 메소드
- Input, Update, Render 메소드에 인자로 들어가는 float DeltaTime변수는 나중에 설명
CGameManager::Update(float DeltaTime)
- 입력에 따른 플레이어 및 게임 오브젝트들의 상태를 업데이트해 주는 메소드
CGameManager::Collision(float DeltaTime)
- 게임 오브젝트 간 충돌 처리 메소드
CGameManager::Render(float DeltaTime)
- 위의 정보들을 토대로 최종적으로 프레임을 그려내는 메소드
위의 4가지 메소드를 Logic() 함수에 추가했으면,
해당 함수들이 반복문에서 계속 실행되도록 해 주자. 일단 이번 글에서는 함수가 반복 실행되기만 하면 된다.
다음 글에서 출력(Render)을 먼저 해볼 예정이다.
변경점이 CGameManager 클래스 뿐이므로 CGameManager 클래스의 헤더와 cpp파일의 코드만 업로드.
//Class CGameManager
//GameManager.h
#pragma once
#include "GameInfo.h"
#include "Singleton.h"
class CGameManager
{
private:
HINSTANCE m_hInst;
HWND m_hWnd;
//static 메소드인 WinProc은 같은 static 변수만 처리가능하므로
static bool m_Loop;
public:
bool Init(HINSTANCE hInstance);
int Run();
private:
void Logic();
void Input(float DeltaTime);
void Update(float DeltaTime);
void Collision(float DeltaTime);
void Render(float DeltaTime);
void Register();
bool Create();
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
DECLARE_SINGLETON(CGameManager)
};
//Class CGameManager
//GameManager.cpp
#include "GameManager.h"
//아이콘
#include "resource.h"
DEFINITION_SINGLETON(CGameManager)
bool CGameManager::m_Loop = true;
CGameManager::CGameManager()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
//_CrtSetBreakAlloc(141);
}
CGameManager::~CGameManager()
{
}
bool CGameManager::Init(HINSTANCE hInstance)
{
m_hInst = hInstance;
// 윈도우클래스 구조체를 만들어주고 등록한다.
Register();
// 윈도우 창을 생성하고 보여준다.
Create();
return true;
}
int CGameManager::Run()
{
MSG msg;
while (m_Loop)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Logic();
}
}
return (int)msg.wParam;
}
void CGameManager::Logic()
{
Input(0.0f);
Update(0.0f);
Collision(0.0f);
Render(0.0f);
}
void CGameManager::Input(float DeltaTime)
{
}
void CGameManager::Update(float DeltaTime)
{
}
void CGameManager::Collision(float DeltaTime)
{
}
void CGameManager::Render(float DeltaTime)
{
}
void CGameManager::Register()
{
// 레지스터에 등록할 윈도우 클래스 구조체를 만들어준다.
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
// 메세지큐에서 꺼내온 메세지를 인자로 전달하며 호출할 함수의 함수 주소를
// 등록한다.
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
// 윈도우 인스턴스를 등록한다.
wcex.hInstance = m_hInst;
// 실행파일에 사용할 아이콘을 등록한다.
wcex.hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_ICON1));
// 마우스 커서 모양을 결정한다.
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
// 메뉴를 사용할지 말지를 결정한다.
wcex.lpszMenuName = nullptr;
// 등록할 클래스의 이름을 유니코드 문자열로 만들어서 지정한다.
// TEXT 매크로는 프로젝트 설정이 유니코드로 되어있을 경우 유니코드 문자열로 만들어지고
// 멀티바이트로 되어있을 경우 멀티바이트 문자열로 만들어지게 된다.
wcex.lpszClassName = TEXT("GameFramework");
// 윈도우창 좌상단에 표시할 작은 아이콘을 등록한다.
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON1));
RegisterClassExW(&wcex);
}
bool CGameManager::Create()
{
m_hWnd = CreateWindowW(TEXT("GameFramework"),
TEXT("GameFramework"), WS_OVERLAPPEDWINDOW,
100, 50, 1280, 720, nullptr, nullptr, m_hInst, nullptr);
if (!m_hWnd)
{
return false;
}
RECT rc = { 0, 0, 1280, 720 };
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
MoveWindow(m_hWnd, 100, 50, abs(rc.left) + abs(rc.right), abs(rc.top) + abs(rc.bottom), true);
// 윈도우 창을 보여준다. 1번인자에 들어간 핸들의 윈도우 창을 보여줄지 말지를
// 결정해준다.
ShowWindow(m_hWnd, SW_SHOW);
// 이 함수를 호출하여 클라이언트 영역이 제대로 갱신되었다면 0이 아닌 값을 반환하고
// 갱신이 실패했을 경우 0을 반환한다.
UpdateWindow(m_hWnd);
return true;
}
LRESULT CGameManager::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
// 윈도우가 종료될때 들어오는 메세지이다.
m_Loop = false;
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
'WIN32API FrameWork > 한단계씩 직접 구현' 카테고리의 다른 글
07. DeltaTime (0) | 2022.05.16 |
---|---|
06. 화면 출력 (0) | 2022.05.16 |
04. crtdbg 헤더를 통한 메모리 누수 잡기 (0) | 2022.05.15 |
03. 창이 생성될때의 사이즈 설정하기 (0) | 2022.05.15 |
*** 공부 방법 *** (0) | 2022.05.15 |