1. 프레임워크 제작 개요

프레임워크 제작의 목표는 게임 메인 루프와 입력, 시간 관리를 체계적으로 만들기 위함입니다. 예제 코드에서는 PeekMessageGetMessage를 비교하여, 논블로킹 환경에서 메시지 처리를 개선하고 게임의 로직을 정상적으로 수행할 수 있도록 메인 루프를 수정하는 것이 핵심입니다.


2. 주요 수정 및 정리 단계

2.1 메인 루프 수정 (PeekMessage 활용)

코드:

MSG msg = {};
while (msg.message != WM_QUIT)
{
    if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    else
    {
        // 게임 로직
    }
}

설명:
1. MSG msg = {};

  • MSG 구조체를 초기화합니다. 이는 메시지 큐에서 가져온 메시지를 저장합니다.
  1. while (msg.message != WM_QUIT)

    • WM_QUIT 메시지가 발생할 때 루프를 빠져나가 프로그램을 종료합니다.
  2. if (::PeekMessage(..., PM_REMOVE))

    • 메시지가 존재하면 큐에서 해당 메시지를 가져와 처리합니다.
    • PM_REMOVE: 메시지를 가져온 뒤 제거합니다.
    • 논블로킹이므로 메시지가 없으면 즉시 반환됩니다.
  3. ::TranslateMessage(&msg)

    • 키보드 입력을 변환합니다.
  4. ::DispatchMessage(&msg)

    • 메시지를 WndProc으로 전달하여 처리합니다.
  5. else

    • 메시지가 없을 경우 게임 로직(예: Update, Render)을 실행합니다.
    • 게임 로직이 메시지 처리와 독립적으로 동작하도록 수정되었습니다.

2.2 폴더 구조 정리

강의에서는 MainGame, Manager, Header 폴더를 나누어 정리했습니다.

  • 00.MainGame: 게임의 메인 로직 (Game.h, Game.cpp)
  • 01.Manager: 시간, 입력 매니저 (TimeManager.h, InputManager.h)
  • 99.Header: 유틸리티와 공용 헤더
    • Utils.h, Types.h, Defines.h, Enums.h

2.3 Defines, Enums, Types 헤더 생성

  1. Defines.h
    • 매크로 정의를 저장합니다.
#pragma once
#define MAX_FPS 60
  1. Enums.h
    • 상태나 입력과 관련된 열거형 정의.
enum class KeyState { None, Press, Down, Up };
  1. Types.h
    • 타입 별칭좌표 구조체를 정의합니다.
#pragma once

using int32 = __int32;

struct Pos
{
    float x = 0;
    float y = 0;
};

2.4 PCH 파일 생성 (미리 컴파일된 헤더)

pch.h:

#pragma once

#include "Types.h"
#include "Defines.h"
#include "Enums.h"
#include <Windows.h>
#include <vector>
#include <string>

설명:

  • 자주 사용되는 헤더 파일을 미리 컴파일하여 빌드 속도를 개선합니다.

3. Utils 클래스 생성

Utils.h:

#pragma once
#include "Types.h"
#include <Windows.h>
#include <string>

class Utils
{
public:
    static void DrawText(HDC hdc, Pos pos, const std::wstring& str);
};

Utils.cpp:

void Utils::DrawText(HDC hdc, Pos pos, const std::wstring& str)
{
    ::TextOut(hdc, static_cast<int32>(pos.x), static_cast<int32>(pos.y), str.c_str(), str.size());
}

4. Manager 클래스 작성

4.1 InputManager

  • 싱글톤 방식으로 키 입력을 관리합니다.
DECLARE_SINGLE(InputManager)
void Update();

Update 함수:

if (::GetKeyboardState(asciiKeys))
{
    for (uint32 key = 0; key < KEY_TYPE_COUNT; key++)
    {
        if (asciiKeys[key] & 0x80) { /* 상태 업데이트 */ }
    }
}

4.2 TimeManager

프레임 시간과 FPS를 계산합니다.

void Update()
{
    uint64 currentCount;
    ::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&currentCount));
    _deltaTime = (currentCount - _prevCount) / static_cast<float>(_frequency);
    _prevCount = currentCount;
}

5. Game 클래스 구현

Game.h:

void Init(HWND hwnd);
void Update();
void Render();

Game.cpp:

void Game::Render()
{
    uint32 fps = GET_SINGLE(TimeManager)->GetFps();
    wstring str = format(L"FPS({0})", fps);
    ::TextOut(_hdc, 20, 10, str.c_str(), str.size());
}

6. 메모리 릭 체크

pch.h에 CRT 디버깅 기능을 활성화:

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>

#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

profile
李家네_공부방

0개의 댓글