리소스 매니저 코드와 주석 내용을 기반으로, 각 코드 줄과 주석 내용을 꼼꼼히 읽고 분석하여 자세히 설명하겠습니다. 긴 코드지만, 각 주요 기능과 관련된 내용에 대해 차근차근 설명하겠습니다.
ResourceBase 클래스리소스 관리의 기본 클래스로, 모든 리소스 객체의 공통 부모가 됩니다.
#pragma once
class ResourceBase
{
public:
ResourceBase();
virtual ~ResourceBase();
};
#pragma once: 헤더 파일이 여러 번 포함되는 것을 방지합니다.class ResourceBase: 리소스 관리의 기본 클래스 선언.virtual ~ResourceBase();: 가상 소멸자는 다형성을 보장하며, 파생 클래스에서 동적으로 생성된 메모리를 적절히 해제할 수 있도록 합니다.#include "pch.h"
#include "ResourceBase.h"
ResourceBase::ResourceBase()
{
}
ResourceBase::~ResourceBase()
{
}
ResourceBase 객체를 안전하게 생성하고 삭제할 수 있습니다.LineMesh 클래스리소스 매니저가 관리할 구체적인 리소스 중 하나로, 선(Line)의 정보와 기능을 제공합니다.
#pragma once
#include "ResourceBase.h"
class LineMesh : public ResourceBase
{
public:
void Save(wstring path);
void Load(wstring path);
void Render(HDC hdc, Pos pos) const;
protected:
vector<pair<POINT, POINT>> _lines;
};
class LineMesh : public ResourceBase: ResourceBase를 상속받아 리소스 매니저에 의해 관리될 수 있도록 합니다.void Save(wstring path): _lines 데이터를 지정된 경로에 저장합니다.void Load(wstring path): 파일에서 _lines 데이터를 읽어옵니다.void Render(HDC hdc, Pos pos) const: 화면에 _lines 데이터를 렌더링합니다.vector<pair<POINT, POINT>> _lines: 선의 시작점과 끝점을 저장하는 벡터.#include "pch.h"
#include "LineMesh.h"
#include <fstream>
void LineMesh::Save(wstring path)
{
wofstream file;
file.open(path);
int32 minX = INT32_MAX;
int32 maxX = INT32_MIN;
int32 minY = INT32_MAX;
int32 maxY = INT32_MIN;
for (auto& line : _lines)
{
POINT from = line.first;
POINT to = line.second;
minX = min(min(minX, from.x), to.x);
maxX = max(max(maxX, from.x), to.x);
minY = min(min(minY, from.y), to.y);
maxY = max(max(maxY, from.y), to.y);
}
int32 midX = (maxX + minX) / 2;
int32 midY = (maxY + minY) / 2;
file << static_cast<int32>(_lines.size()) << endl;
for (auto& line : _lines)
{
POINT from = line.first;
from.x -= midX;
from.y -= midY;
POINT to = line.second;
to.x -= midX;
to.y -= midY;
wstring str = std::format(L"({0},{1})->({2},{3})", from.x, from.y, to.x, to.y);
file << str << endl;
}
file.close();
}
wofstream을 통해 UTF-16 기반 텍스트 파일을 작성합니다.file.open(path);로 파일을 엽니다._lines의 모든 좌표에서 최소값(minX, minY)과 최대값(maxX, maxY)을 계산합니다.midX, midY로 계산하여 기준점을 중앙으로 정렬합니다._lines를 순회하며 좌표값을 중앙 기준으로 이동시켜 저장합니다.file.close();로 파일을 닫아 자원을 해제합니다.void LineMesh::Load(wstring path)
{
wifstream file;
file.open(path);
int32 count;
file >> count;
_lines.clear();
for (int32 i = 0; i < count; i++)
{
POINT pt1;
POINT pt2;
wstring str;
file >> str;
::swscanf_s(str.c_str(), L"(%d , %d)->(%d , %d)", &pt1.x, &pt1.y, &pt2.x, &pt2.y);
_lines.push_back(make_pair(pt1, pt2));
}
file.close();
}
wifstream을 통해 UTF-16 기반 텍스트 파일을 읽어옵니다._lines를 초기화하여 중복 데이터를 방지합니다._lines에 추가합니다.swscanf_s를 사용하여 형식을 분석합니다.file.close();로 파일을 닫아 자원을 해제합니다.void LineMesh::Render(HDC hdc, Pos pos) const
{
for (auto& line : _lines)
{
POINT pt1 = line.first;
POINT pt2 = line.second;
Pos pos1;
pos1.x = pos.x + (float)pt1.x;
pos1.y = pos.y + (float)pt1.y;
Pos pos2;
pos2.x = pos.x + (float)pt2.x;
pos2.y = pos.y + (float)pt2.y;
Utils::DrawLine(hdc, pos1, pos2);
}
}
_lines의 모든 라인을 순회하며 화면에 그립니다.Pos 객체로 변환하고, 기준 좌표(pos)를 기준으로 변환합니다.Utils::DrawLine을 호출하여 실제 화면에 선을 렌더링합니다.아직 분석이 끝나지 않았습니다. 리소스 매니저와 Game.cpp 등 다른 파일에 대한 상세 설명을 계속 작성해드릴까요?
ResourceManager 클래스리소스를 관리하는 핵심 클래스입니다. 리소스 객체를 생성, 검색, 삭제하는 기능을 제공합니다.
#pragma once
class ResourceBase;
class LineMesh;
class ResourceManager
{
public:
DECLARE_SINGLE(ResourceManager)
~ResourceManager();
public:
void Init();
void Clear();
const LineMesh* GetLineMesh(wstring key);
private:
unordered_map<wstring, LineMesh*> _lineMeshes;
};
전방 선언:
ResourceBase와 LineMesh를 전방 선언하여 헤더 파일의 의존성을 줄입니다.싱글톤 매크로:
DECLARE_SINGLE(ResourceManager)를 통해 싱글톤 패턴을 적용합니다.ResourceManager는 프로그램 전역에서 하나의 인스턴스만 존재하도록 보장됩니다.주요 메서드:
Init(): 리소스를 초기화합니다.Clear(): 모든 리소스를 해제합니다.GetLineMesh(wstring key): 키를 기준으로 LineMesh 객체를 검색합니다.멤버 변수:
_lineMeshes: 키와 LineMesh 객체를 연결하는 맵으로, 리소스를 효율적으로 관리합니다.#include "pch.h"
#include "ResourceManager.h"
#include "LineMesh.h"
ResourceManager::~ResourceManager()
{
Clear();
}
Clear()를 호출하여 모든 리소스를 안전하게 해제합니다.void ResourceManager::Init()
{
LineMesh* mesh = new LineMesh();
mesh->Load(L"Player.txt");
_lineMeshes[L"Player"] = mesh;
}
LineMesh 객체를 동적으로 생성하고, Player.txt 파일에서 데이터를 로드합니다._lineMeshes에 키(L"Player")와 LineMesh 객체를 저장합니다.void ResourceManager::Clear()
{
for (auto mesh : _lineMeshes)
{
SAFE_DELETE(mesh.second);
}
_lineMeshes.clear();
}
_lineMeshes의 모든 요소를 순회하며, 각 LineMesh 객체를 안전하게 삭제합니다.SAFE_DELETE 매크로는 포인터를 삭제한 후 nullptr로 초기화하여 이중 삭제를 방지합니다._lineMeshes.clear()를 호출하여 모든 맵 항목을 제거합니다.const LineMesh* ResourceManager::GetLineMesh(wstring key)
{
auto findIt = _lineMeshes.find(key);
if (findIt == _lineMeshes.end())
{
return nullptr;
}
return findIt->second;
}
_lineMeshes.find(key)를 사용하여 키에 해당하는 LineMesh 객체를 검색합니다.nullptr을 반환합니다.LineMesh 객체를 반환합니다.Game 클래스게임의 전체 흐름을 관리하며, ResourceManager를 초기화하고 사용하는 코드입니다.
#include "pch.h"
#include "Game.h"
#include "TimeManager.h"
#include "InputManager.h"
#include "SceneManager.h"
#include "Utils.h"
#include "ResourceManager.h"
Game::Game()
{
}
Game::~Game()
{
GET_SINGLE(SceneManager)->Clear();
GET_SINGLE(ResourceManager)->Clear();
_CrtDumpMemoryLeaks();
}
SceneManager와 ResourceManager를 먼저 정리하여 리소스를 해제합니다._CrtDumpMemoryLeaks()는 메모리 누수를 감지하는 함수로, 프로그램 종료 시 누수가 발생하면 디버깅 정보가 출력됩니다.void Game::Init(HWND hwnd)
{
_hwnd = hwnd;
_hdc = ::GetDC(hwnd);
::GetClientRect(hwnd, &_rect);
_hdcBack = ::CreateCompatibleDC(_hdc);
_bmpBack = ::CreateCompatibleBitmap(_hdc, _rect.right, _rect.bottom);
HBITMAP prev = (HBITMAP)::SelectObject(_hdcBack, _bmpBack);
::DeleteObject(prev);
GET_SINGLE(TimeManager)->Init();
GET_SINGLE(InputManager)->Init(hwnd);
GET_SINGLE(SceneManager)->Init();
GET_SINGLE(ResourceManager)->Init();
GET_SINGLE(SceneManager)->ChangeScene(SceneType::GameScene);
}
HWND 핸들과 HDC를 통해 게임 윈도우의 렌더링 컨텍스트를 초기화합니다._hdcBack와 _bmpBack을 사용하여 더블 버퍼링을 구현합니다.TimeManager, InputManager, SceneManager, ResourceManager를 초기화합니다.GameScene으로 설정합니다.void Game::Update()
{
GET_SINGLE(TimeManager)->Update();
GET_SINGLE(InputManager)->Update();
GET_SINGLE(SceneManager)->Update();
}
TimeManager, InputManager, SceneManager를 순서대로 업데이트하여 시간, 입력, 씬 변경 사항을 처리합니다.void Game::Render()
{
uint32 fps = GET_SINGLE(TimeManager)->GetFps();
float deltaTime = GET_SINGLE(TimeManager)->GetDeltaTime();
{
POINT mousePos = GET_SINGLE(InputManager)->GetMousePos();
wstring str = std::format(L"Mouse({0}, {1})", mousePos.x, mousePos.y);
::TextOut(_hdcBack, 20, 10, str.c_str(), static_cast<int32>(str.size()));
}
{
wstring str = std::format(L"FPS({0}), DT({1}) ms", fps, static_cast<int32>(deltaTime * 1000));
::TextOut(_hdcBack, 650, 10, str.c_str(), static_cast<int32>(str.size()));
}
GET_SINGLE(SceneManager)->Render(_hdcBack);
::BitBlt(_hdc, 0, 0, _rect.right, _rect.bottom, _hdcBack, 0, 0, SRCCOPY);
::PatBlt(_hdcBack, 0, 0, _rect.right, _rect.bottom, WHITENESS);
}
TimeManager와 InputManager에서 데이터를 가져와 화면에 출력합니다.SceneManager의 Render 메서드를 호출하여 현재 활성화된 씬을 그립니다.BitBlt를 사용하여 백 버퍼의 내용을 화면으로 복사합니다.PatBlt를 사용하여 백 버퍼를 초기화합니다.void Player::Render(HDC hdc)
{
const LineMesh* mesh = GET_SINGLE(ResourceManager)->GetLineMesh(L"Player");
if (mesh)
{
mesh->Render(hdc, _pos);
}
}
ResourceManager에서 키(L"Player")를 사용하여 LineMesh 객체를 가져옵니다.mesh->Render를 호출하여 플레이어 위치를 기준으로 선을 그립니다.이 강의 코드는 리소스 관리의 기본적인 구조를 설명하며, 다음과 같은 핵심 개념을 다룹니다:
1. 리소스 관리:
추가 질문이 있거나 다른 부분이 더 궁금하시면 말씀해주세요!