Game 폴더에 넣음. 이는 리소스가 엔진 관련이 아니라 콘텐츠 관련임을 암시.pch.h(precompiled header)에 추가하여 모든 소스 파일에서 쉽게 접근 가능하게 함.Game 내 Fortress 폴더 생성.MenuScene: 게임 시작 시 표시되는 메뉴 화면.FortressScene: 게임 화면.Scene 클래스를 상속받아 구현.MenuScene이 기본적으로 표시되도록 설정.enum을 사용하여 직업군 타입 관리.전체적으로 방대한 코드와 설명을 완벽히 한 줄 한 줄 꼼꼼하게 설명하려면 상당한 분량과 시간이 소요됩니다. 지금부터 요청에 따라 한 줄 한 줄 꼼꼼하게 분석과 설명을 시작하겠습니다. 한 번에 모든 내용을 다루기보다는, 먼저 필요한 부분부터 진행하며 이후 요청에 따라 다른 부분으로 이어 나가겠습니다.
이 설명은 제공된 목차와 내용을 기반으로 차례대로 진행하며, 모든 코드의 의미를 세세히 다룹니다.
#pragma once
const int32 GWinSizeX = 800;
const int32 GWinSizeY = 600;
const int32 GMinimapSizeX = 200;
const int32 GMinimapSizeY = 128;
const float PI = 3.1415926f;
#pragma once
#ifndef ... #define)를 대체하는 현대적인 방식입니다.const int32 GWinSizeX = 800;
800으로 설정합니다. int32: 32비트 정수형 타입(정확한 크기를 보장).const int32 GWinSizeY = 600;
600으로 설정합니다. const int32 GMinimapSizeX = 200;
200으로 설정합니다. const int32 GMinimapSizeY = 128;
128로 설정합니다. const float PI = 3.1415926f;
PI 값을 정의하여 각도나 원 관련 수학 연산에서 사용됩니다. float 타입으로 정의하여 소수점 계산 시 유효 숫자를 제한. LineMesh 클래스#pragma once
#include "ResourceBase.h"
class LineMesh : public ResourceBase
{
public:
void Save(wstring path);
void Load(wstring path);
void Render(HDC hdc, Pos pos, float ratioX = 1.0f, float ratioY = 1.0f) const;
vector<pair<POINT, POINT>>& GetLines() { return _lines; }
protected:
vector<pair<POINT, POINT>> _lines;
int32 _width = 0;
int32 _height = 0;
};
#pragma once
#include "ResourceBase.h"
LineMesh 클래스가 상속받는 ResourceBase 클래스의 정의를 가져옵니다. ResourceBase는 모든 리소스의 공통 동작(로드, 저장 등)을 정의한 베이스 클래스입니다.class LineMesh : public ResourceBase
LineMesh는 ResourceBase의 자식 클래스이며, 선 메쉬(Line Mesh)를 관리하는 역할을 합니다. public:
void Save(wstring path);
_lines 데이터를 주어진 경로(path)의 파일에 저장합니다. wstring: 유니코드 문자열 타입으로, 다국어 파일 경로를 지원합니다.void Load(wstring path);
_lines 데이터를 읽어옵니다. void Render(HDC hdc, Pos pos, float ratioX = 1.0f, float ratioY = 1.0f) const;
HDC(디바이스 컨텍스트)를 사용해 _lines 데이터를 화면에 렌더링합니다. Pos pos: 렌더링 시작 좌표를 설정합니다. ratioX, ratioY: 가로 및 세로 비율로, 기본값은 1.0(기본 크기)입니다.vector<pair<POINT, POINT>>& GetLines();
_lines 멤버 변수(선 데이터 벡터)의 참조를 반환합니다. pair<POINT, POINT>: 각 선의 시작점(POINT)과 끝점(POINT)을 저장. _lines를 수정하거나 읽어야 할 때 사용됩니다.protected:
vector<pair<POINT, POINT>> _lines;
POINT: Windows API에서 사용하는 2D 좌표 구조체. pair)으로 표현합니다.int32 _width = 0;
0으로 설정.int32 _height = 0;
0으로 설정.Save 함수void LineMesh::Save(wstring path)
{
wofstream file;
file.open(path);
int32 minX = INT32_MAX, maxX = INT32_MIN, minY = INT32_MAX, 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 file;
file.open(path);
path)의 파일을 엽니다. int32 minX = INT32_MAX, maxX = INT32_MIN, minY = INT32_MAX, maxY = INT32_MIN;
_lines의 모든 선 데이터를 기준으로 최소/최대 x, y 좌표값을 초기화합니다.for (auto& line : _lines)
_lines 벡터를 순회하며 각 선 데이터를 처리합니다.POINT from = line.first;
POINT to = line.second;
Save 함수**minX = min(min(minX, from.x), to.x);
minX(최소 x 좌표값)를 업데이트합니다. from.x)과 끝점(to.x) 중 더 작은 값을 비교하고, minX보다 작으면 업데이트합니다. _lines 내 모든 선의 좌표를 정규화(중앙 좌표 기준 변환)하기 위해 최소값을 계산합니다.maxX = max(max(maxX, from.x), to.x);
maxX(최대 x 좌표값)를 업데이트합니다. from.x)과 끝점(to.x) 중 더 큰 값을 비교하고, maxX보다 크면 업데이트합니다. minY = min(min(minY, from.y), to.y);
minY(최소 y 좌표값)를 업데이트합니다. from.y)과 끝점(to.y) 중 더 작은 값을 비교하고, minY보다 작으면 업데이트합니다.maxY = max(max(maxY, from.y), to.y);
maxY(최대 y 좌표값)를 업데이트합니다. from.y)과 끝점(to.y) 중 더 큰 값을 비교하고, maxY보다 크면 업데이트합니다.int32 midX = (maxX + minX) / 2;
midX)를 계산합니다. (maxX + minX) / 2는 x 좌표의 중앙값입니다. midX를 빼면 중앙 기준으로 이동합니다.int32 midY = (maxY + minY) / 2;
midY)를 계산합니다.file << static_cast<int32>(_lines.size()) << endl;
_lines에 저장된 선의 개수를 파일의 첫 번째 줄에 기록합니다. for (auto& line : _lines)
_lines 벡터를 순회하며 각 선 데이터를 파일에 저장합니다.POINT from = line.first;
from.x -= midX; from.y -= midY;
from.x -= midX: x 좌표에서 중앙 x 좌표(midX)를 빼서 정규화. from.y -= midY: y 좌표에서 중앙 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);
(from.x, from.y)->(to.x, to.y).file << str << endl;
file.close();
Load 함수 분석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 = {}, 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 file;
file.open(path);
path)의 파일을 엽니다.int32 count;
file >> count;
_lines.clear();
_lines 데이터를 모두 제거합니다. for (int32 i = 0; i < count; i++)
POINT pt1 = {}, pt2 = {};
pt1)과 끝점(pt2) 좌표를 저장할 변수를 선언 및 초기화합니다.wstring str;
file >> str;
::swscanf_s(str.c_str(), L"(%d,%d)->(%d,%d)", &pt1.x, &pt1.y, &pt2.x, &pt2.y);
str)을 파싱하여 시작점(pt1)과 끝점(pt2)의 좌표값을 추출합니다. (%d,%d)->(%d,%d) 형식을 사용하여 좌표 데이터를 구분합니다._lines.push_back(make_pair(pt1, pt2));
pair로 묶어 _lines 벡터에 추가합니다.file.close();
계속해서 요청하신 다른 함수와 클래스에 대해 꼼꼼히 설명하겠습니다. 이어서 다룰 함수와 클래스 목록을 명시하거나 요청하시면 그 순서대로 진행하겠습니다. 우선 요청에 포함될 가능성이 높은 부분부터 차례로 진행하겠습니다.
LineMesh::Render 함수void LineMesh::Render(HDC hdc, Pos pos, float ratioX, float ratioY) const
{
for (auto& line : _lines)
{
POINT pt1 = line.first;
POINT pt2 = line.second;
Pos pos1 = { pos.x + static_cast<float>(pt1.x) * ratioX, pos.y + static_cast<float>(pt1.y) * ratioY };
Pos pos2 = { pos.x + static_cast<float>(pt2.x) * ratioX, pos.y + static_cast<float>(pt2.y) * ratioY };
Utils::DrawLine(hdc, pos1, pos2);
}
}
void LineMesh::Render(HDC hdc, Pos pos, float ratioX, float ratioY) const LineMesh에 저장된 선 데이터를 화면에 그립니다.HDC hdc: Pos pos: float ratioX, float ratioY: const: for (auto& line : _lines)
_lines 벡터를 순회하며 각 선을 화면에 그립니다._lines는 선 데이터(시작점과 끝점의 좌표)를 저장한 vector<pair<POINT, POINT>>입니다.POINT pt1 = line.first;
pt1에 저장합니다.POINT pt2 = line.second;
pt2에 저장합니다.Pos pos1 = { pos.x + static_cast<float>(pt1.x) * ratioX, pos.y + static_cast<float>(pt1.y) * ratioY };
pt1)를 기준 위치(pos)와 비율(ratioX, ratioY)에 따라 조정합니다.pt1.x 좌표를 ratioX로 조정하고, 기준 x 좌표(pos.x)를 더합니다.pt1.y 좌표도 동일하게 조정합니다.Pos pos2 = { pos.x + static_cast<float>(pt2.x) * ratioX, pos.y + static_cast<float>(pt2.y) * ratioY };
pt2)를 기준 위치(pos)와 비율(ratioX, ratioY)에 따라 조정합니다.Utils::DrawLine(hdc, pos1, pos2);
Utils 클래스의 DrawLine 함수를 호출하여, 시작점(pos1)과 끝점(pos2)을 연결하는 선을 화면에 그립니다.hdc)에 선을 그립니다.Object 클래스class Object
{
public:
Object(ObjectType type);
virtual ~Object();
virtual void Init() abstract;
virtual void Update() abstract;
virtual void Render(HDC hdc) abstract;
ObjectType GetObjectType() { return _type; }
Vector GetPos() { return _pos; }
void SetPos(Vector pos) { _pos = pos; }
float GetRadius() { return _radius; }
protected:
ObjectType _type = ObjectType::None;
MoveDir _dir = MoveDir::Right;
Stat _stat = {};
Vector _pos = {};
float _radius = 0.f;
};
class Object
Init, Update, Render는 순수 가상 함수(= abstract)로 선언되어 있습니다. 이를 상속받은 클래스에서 반드시 구현해야 합니다.public:
Object(ObjectType type);
type)을 초기화합니다.ObjectType은 플레이어, 발사체 등 객체의 종류를 나타내는 열거형(enum) 타입으로 추정됩니다.virtual ~Object();
virtual void Init() abstract;
virtual void Update() abstract;
virtual void Render(HDC hdc) abstract;
ObjectType GetObjectType() { return _type; }
_type)을 반환합니다. Vector GetPos() { return _pos; }
_pos)를 반환합니다. Vector 타입: void SetPos(Vector pos) { _pos = pos; }
float GetRadius() { return _radius; }
_radius)을 반환합니다. ObjectType _type = ObjectType::None;
ObjectType::Player, ObjectType::Bullet 등. ObjectType::None(기본값).MoveDir _dir = MoveDir::Right;
MoveDir::Left, MoveDir::Right.Stat _stat = {};
hp), 속도(speed) 등의 데이터를 포함하는 구조체.Vector _pos = {};
float _radius = 0.f;
다음으로 다룰 클래스 또는 함수에 대한 요청 사항을 알려주시면, 이어서 꼼꼼히 한 줄씩 분석해 드리겠습니다.
예:
Player 클래스 SceneManager 클래스 Bullet::Update, FortressScene::ChangePlayerTurn 등)이제 설명하지 않은 클래스와 함수들을 계속해서 꼼꼼히 설명하겠습니다. 아래는 남은 클래스와 함수들의 목록입니다. 순서대로 진행하며 한 줄 한 줄 설명하겠습니다.
Player 클래스class Player : public Object
{
public:
Player();
virtual ~Player() override;
virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
wstring GetMeshKey();
void SetPlayerId(int32 playerId);
void SetPlayerType(PlayerType playerType);
void SetPlayerTurn(bool playerTurn);
int32 GetPlayerId();
PlayerType GetPlayerType();
bool GetPlayerTurn();
private:
void UpdateFireAngle();
private:
int32 _playerId = 0;
PlayerType _playerType = PlayerType::MissileTank;
bool _playerTurn = false;
float _fireAngle = 0.f;
};
class Player : public Object
Player는 게임의 플레이어 오브젝트를 나타내며, Object 클래스를 상속받아 구현되었습니다.Object 클래스의 공통 기능(위치, 충돌 반지름, 렌더링 등)을 재사용.public:
Player();
Player 클래스의 생성자로, 초기화를 담당합니다.virtual ~Player() override;
Player 클래스의 소멸자로, 부모 클래스의 소멸자와 함께 호출됩니다.virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
hdc를 사용하여 그래픽을 그립니다.wstring GetMeshKey();
void SetPlayerId(int32 playerId);
void SetPlayerType(PlayerType playerType);
MissileTank, CannonTank 등)을 설정합니다.void SetPlayerTurn(bool playerTurn);
int32 GetPlayerId();
PlayerType GetPlayerType();
MissileTank, CannonTank 등)을 반환합니다.bool GetPlayerTurn();
void UpdateFireAngle();
Player::Init 함수void Player::Init()
{
_stat.hp = 100;
_stat.maxHp = 100;
_stat.speed = 500;
_pos.x = 0;
_pos.y = 0;
_radius = 50.f;
_fireAngle = 30.f;
}
_stat.hp = 100;
_stat.maxHp = 100;
_stat.speed = 500;
_pos.x = 0;, _pos.y = 0;
(0, 0)으로 설정합니다._radius = 50.f;
_fireAngle = 30.f;
Player::Update 함수void Player::Update()
{
float deltaTime = GET_SINGLE(TimeManager)->GetDeltaTime();
if (GET_SINGLE(InputManager)->GetButton(KeyType::A))
{
_pos.x -= _stat.speed * deltaTime;
_dir = MoveDir::Left;
}
if (GET_SINGLE(InputManager)->GetButton(KeyType::D))
{
_pos.x += _stat.speed * deltaTime;
_dir = MoveDir::Right;
}
if (GET_SINGLE(InputManager)->GetButton(KeyType::SpaceBar))
{
float percent = GET_SINGLE(UIManager)->GetPowerPercent();
percent = min(100, percent + 100 * deltaTime);
GET_SINGLE(UIManager)->SetPowerPercent(percent);
}
}
float deltaTime = GET_SINGLE(TimeManager)->GetDeltaTime();
if (GET_SINGLE(InputManager)->GetButton(KeyType::A))
A 키가 눌렸는지 확인합니다._pos.x -= _stat.speed * deltaTime;
_dir = MoveDir::Left;
if (GET_SINGLE(InputManager)->GetButton(KeyType::D))
D 키가 눌렸는지 확인합니다._pos.x += _stat.speed * deltaTime;
_dir = MoveDir::Right;
if (GET_SINGLE(InputManager)->GetButton(KeyType::SpaceBar))
float percent = GET_SINGLE(UIManager)->GetPowerPercent();
percent = min(100, percent + 100 * deltaTime);
GET_SINGLE(UIManager)->SetPowerPercent(percent);
SceneManager 클래스class SceneManager
{
DECLARE_SINGLE(SceneManager);
public:
void Init();
void Update();
void Render(HDC hdc);
void Clear();
void ChangeScene(SceneType sceneType);
Scene* GetCurrentScene();
private:
Scene* _scene;
SceneType _sceneType = SceneType::None;
};
DECLARE_SINGLE(SceneManager)
SceneManager는 하나의 인스턴스만 생성됩니다.void Init();
void Update();
void Render(HDC hdc);
void Clear();
void ChangeScene(SceneType sceneType);
Scene* GetCurrentScene();
Scene* _scene;
SceneType _sceneType = SceneType::None;
위 클래스와 함수에 이어 분석하지 않은 부분(예: Bullet, FortressScene)을 포함하여 계속 분석하겠습니다.
추가 요청 사항을 알려주시면 해당 내용을 우선적으로 진행합니다!
계속해서 남은 클래스와 함수에 대해 꼼꼼히 설명하겠습니다. 아래는 아직 다루지 않은 주요 클래스와 함수에 대한 분석입니다.
Bullet 클래스class Bullet : public Object
{
public:
Bullet();
~Bullet();
virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
Vector GetSpeed();
void SetSpeed(Vector speed);
void SetOwner(Object* owner);
Object* GetOwner();
protected:
Vector _speed = {};
Object* _owner = nullptr;
};
class Bullet : public Object
Bullet은 게임 내 발사체(총알, 미사일 등)를 나타내며, Object를 상속받아 구현되었습니다.Object로부터 상속받아 재사용합니다.Bullet();
Bullet의 생성자로, 초기화를 수행합니다.~Bullet();
Bullet의 소멸자로, 리소스 해제를 처리합니다.virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
Vector GetSpeed();, void SetSpeed(Vector speed);
void SetOwner(Object* owner);, Object* GetOwner();
Bullet::Init 함수void Bullet::Init()
{
_radius = 10.f;
}
Bullet::Update 함수void Bullet::Update()
{
float deltaTime = GET_SINGLE(TimeManager)->GetDeltaTime();
_pos += _speed * deltaTime; // 현재 속도와 경과 시간을 기반으로 위치 갱신
_speed.y += 1000 * deltaTime; // 중력 효과 추가
const vector<Object*>& objects = GET_SINGLE(ObjectManager)->GetObjects();
for (Object* object : objects)
{
if (object->GetObjectType() != ObjectType::Player)
continue;
if (object == _owner)
continue;
Vector dir = _pos - object->GetPos();
if (dir.Length() < _radius + object->GetRadius())
{
auto* scene = dynamic_cast<FortressScene*>(GET_SINGLE(SceneManager)->GetCurrentScene());
if (scene)
scene->ChangePlayerTurn();
GET_SINGLE(ObjectManager)->Remove(this);
return;
}
}
if (_pos.y > GWinSizeY * 1.5f)
{
auto* scene = dynamic_cast<FortressScene*>(GET_SINGLE(SceneManager)->GetCurrentScene());
if (scene)
scene->ChangePlayerTurn();
GET_SINGLE(ObjectManager)->Remove(this);
return;
}
}
float deltaTime = GET_SINGLE(TimeManager)->GetDeltaTime();
_pos += _speed * deltaTime;
_speed.y += 1000 * deltaTime;
충돌 감지 루프
object->GetObjectType() != ObjectType::Player: object == _owner: dir.Length() < _radius + object->GetRadius(): dir.Length())가 두 객체의 반지름 합보다 작으면 충돌로 간주합니다.GET_SINGLE(ObjectManager)->Remove(this);
if (_pos.y > GWinSizeY * 1.5f)
FortressScene 클래스class FortressScene : public Scene
{
public:
FortressScene();
virtual ~FortressScene() override;
virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
void ChangePlayerTurn();
private:
int32 _playerTurn = 0;
float _sumTime = 0.f;
};
class FortressScene : public Scene
Scene 클래스를 상속받아 구현되었습니다.Init, Update, Render와 같은 공통 작업을 재사용.FortressScene();
FortressScene의 생성자로, 초기화를 수행합니다.virtual ~FortressScene() override;
FortressScene의 소멸자로, 리소스 해제를 처리합니다.virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
void ChangePlayerTurn();
FortressScene::Init 함수void FortressScene::Init()
{
GET_SINGLE(UIManager)->Init();
Player* player1 = GET_SINGLE(ObjectManager)->CreateObject<Player>();
player1->SetPlayerId(0);
player1->SetPos({100, 400});
player1->SetPlayerTurn(true);
GET_SINGLE(ObjectManager)->Add(player1);
Player* player2 = GET_SINGLE(ObjectManager)->CreateObject<Player>();
player2->SetPlayerId(1);
player2->SetPos({700, 400});
player2->SetPlayerTurn(false);
GET_SINGLE(ObjectManager)->Add(player2);
_playerTurn = 0;
}
GET_SINGLE(UIManager)->Init();
플레이어 생성
FortressScene::ChangePlayerTurn 함수void FortressScene::ChangePlayerTurn()
{
_playerTurn = (_playerTurn + 1) % 2;
const auto& objects = GET_SINGLE(ObjectManager)->GetObjects();
for (auto* object : objects)
{
if (object->GetObjectType() != ObjectType::Player)
continue;
Player* player = static_cast<Player*>(object);
player->SetPlayerTurn(player->GetPlayerId() == _playerTurn);
}
GET_SINGLE(UIManager)->SetRemainTime(10);
}
_playerTurn = (_playerTurn + 1) % 2;
0, 1) 사이에서 순환합니다.플레이어 상태 업데이트
위에 설명하지 않은 다른 부분에 대해 더 요청하시면 계속해서 상세히 분석하겠습니다.
아직 다루지 않은 클래스와 함수들을 모두 설명하겠습니다. 아래는 분석이 필요한 모든 클래스를 꼼꼼히 다룬 목록입니다. 각각의 클래스와 함수에 대해 한 줄 한 줄 세세히 분석하겠습니다.
Scene 클래스class Scene
{
public:
Scene() = default;
virtual ~Scene() = default;
virtual void Init() = 0;
virtual void Update() = 0;
virtual void Render(HDC hdc) = 0;
};
class Scene
MenuScene, FortressScene 등)의 기본 구조를 제공하는 추상 클래스입니다. Init, Update, Render를 자식 클래스에서 반드시 구현해야 합니다.Scene() = default;
virtual ~Scene() = default;
virtual void Init() = 0;
virtual void Update() = 0;
virtual void Render(HDC hdc) = 0;
MenuScene 클래스class MenuScene : public Scene
{
public:
MenuScene();
virtual ~MenuScene() override;
virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
};
class MenuScene : public Scene
Scene을 상속받아 구현되었습니다.MenuScene();
MenuScene의 생성자로, 필요한 초기화를 수행합니다.virtual ~MenuScene() override;
MenuScene의 소멸자로, 리소스 해제를 처리합니다.virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
MenuScene::Update 함수void MenuScene::Update()
{
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::E))
{
GET_SINGLE(SceneManager)->ChangeScene(SceneType::FortressScene);
}
}
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::E))
E 키를 눌렀는지 확인합니다.GET_SINGLE(SceneManager)->ChangeScene(SceneType::FortressScene);
FortressScene으로 변경합니다.MenuScene::Render 함수void MenuScene::Render(HDC hdc)
{
::Rectangle(hdc, 0, 0, GWinSizeX, GWinSizeY);
const LineMesh* mesh = GET_SINGLE(ResourceManager)->GetLineMesh(L"Menu");
if (mesh)
mesh->Render(hdc, Pos{ 0, 0 });
HFONT myFont = ::CreateFont(30, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, L"궁서체");
HFONT oldFont = (HFONT)::SelectObject(hdc, myFont);
wstring message = L"PRESS 'E' TO START.";
::TextOut(hdc, 250, 550, message.c_str(), static_cast<int32>(message.size()));
::SelectObject(hdc, oldFont);
::DeleteObject(myFont);
}
::Rectangle(hdc, 0, 0, GWinSizeX, GWinSizeY);
const LineMesh* mesh = GET_SINGLE(ResourceManager)->GetLineMesh(L"Menu");
Menu 메쉬 데이터를 가져옵니다.if (mesh)
mesh->Render(hdc, Pos{ 0, 0 });
HFONT myFont = ::CreateFont(30, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, L"궁서체");
wstring message = L"PRESS 'E' TO START.";
E 키를 누르라는 메시지를 저장합니다.::TextOut(hdc, 250, 550, message.c_str(), static_cast<int32>(message.size()));
UIManager 클래스class UIManager
{
DECLARE_SINGLE(UIManager);
public:
void Init();
void Render(HDC hdc);
void SetWindPercent(float windPercent);
void SetPowerPercent(float powerPercent);
void SetRemainTime(int32 remainTime);
float GetWindPercent();
float GetPowerPercent();
int32 GetRemainTime();
private:
float _windPercent = 0.f;
float _powerPercent = 0.f;
int32 _remainTime = 0;
};
DECLARE_SINGLE(UIManager)
UIManager를 싱글톤으로 선언합니다. void Init();
void Render(HDC hdc);
void SetWindPercent(float windPercent);
void SetPowerPercent(float powerPercent);
void SetRemainTime(int32 remainTime);
float GetWindPercent();
float GetPowerPercent();
int32 GetRemainTime();
여기까지 주요 클래스와 함수들의 상세 분석을 진행하였습니다. 추가적으로 설명이 필요한 부분이나 더 다뤄야 할 클래스/함수가 있다면 알려주세요! ResourceManager와 같은 관리 클래스가 아직 추가로 분석되지 않았다면 이어서 다룰 수 있습니다.
아직 남아 있는 클래스들을 모두 분석하겠습니다. 아래는 아직 다루지 않은 주요 클래스와 함수들입니다. 한 줄씩 철저히 분석을 이어가겠습니다.
ResourceManager 클래스class ResourceManager
{
DECLARE_SINGLE(ResourceManager);
public:
~ResourceManager();
void Init();
void Clear();
const LineMesh* GetLineMesh(wstring key);
private:
unordered_map<wstring, LineMesh*> _lineMeshes;
};
DECLARE_SINGLE(ResourceManager)
ResourceManager를 싱글톤으로 선언합니다. ResourceManager 인스턴스만 존재하도록 보장합니다.~ResourceManager();
_lineMeshes)의 메모리를 해제합니다.void Init();
void Clear();
const LineMesh* GetLineMesh(wstring key);
key)에 해당하는 메쉬 데이터를 반환합니다. nullptr을 반환합니다.unordered_map<wstring, LineMesh*> _lineMeshes;
wstring)는 메쉬 이름, 값(LineMesh*)는 메쉬 데이터의 포인터입니다.ResourceManager::Init 함수void ResourceManager::Init()
{
LineMesh* mesh = new LineMesh();
mesh->Load(L"Menu.txt");
_lineMeshes[L"Menu"] = mesh;
mesh = new LineMesh();
mesh->Load(L"UI.txt");
_lineMeshes[L"UI"] = mesh;
mesh = new LineMesh();
mesh->Load(L"MissileTank.txt");
_lineMeshes[L"MissileTank"] = mesh;
mesh = new LineMesh();
mesh->Load(L"CanonTank.txt");
_lineMeshes[L"CanonTank"] = mesh;
}
LineMesh* mesh = new LineMesh();
LineMesh 객체를 생성합니다.mesh->Load(L"Menu.txt");
Menu.txt 파일에서 메쉬 데이터를 로드합니다._lineMeshes[L"Menu"] = mesh;
Menu라는 키로 메쉬 데이터를 저장합니다.같은 작업 반복
UI.txt, MissileTank.txt, CanonTank.txt)을 로드하여 _lineMeshes에 저장합니다.ResourceManager::GetLineMesh 함수const LineMesh* ResourceManager::GetLineMesh(wstring key)
{
auto findIt = _lineMeshes.find(key);
if (findIt == _lineMeshes.end())
return nullptr;
return findIt->second;
}
auto findIt = _lineMeshes.find(key);
_lineMeshes에서 주어진 키(key)를 검색합니다.if (findIt == _lineMeshes.end())
_lineMeshes에 없으면 nullptr을 반환합니다.return findIt->second;
ResourceManager::Clear 함수void ResourceManager::Clear()
{
for (auto& pair : _lineMeshes)
{
delete pair.second;
}
_lineMeshes.clear();
}
for (auto& pair : _lineMeshes)
_lineMeshes에 저장된 모든 메쉬 데이터를 순회합니다.delete pair.second;
_lineMeshes.clear();
_lineMeshes 맵을 비웁니다.ObjectManager 클래스class ObjectManager
{
DECLARE_SINGLE(ObjectManager);
public:
void Init();
void Update();
void Render(HDC hdc);
void Clear();
template <typename T>
T* CreateObject();
void Add(Object* object);
void Remove(Object* object);
const vector<Object*>& GetObjects() const;
private:
vector<Object*> _objects;
};
DECLARE_SINGLE(ObjectManager)
ObjectManager를 싱글톤으로 선언합니다.void Init();
void Update();
void Render(HDC hdc);
void Clear();
template <typename T> T* CreateObject();
T는 생성할 오브젝트의 타입입니다.void Add(Object* object);
_objects에 추가합니다.void Remove(Object* object);
_objects에서 제거합니다.const vector<Object*>& GetObjects() const;
vector<Object*> _objects;
ObjectManager::Update 함수void ObjectManager::Update()
{
for (Object* object : _objects)
{
object->Update();
}
}
for (Object* object : _objects)
_objects에 저장된 모든 오브젝트를 순회합니다.object->Update();
Update 함수를 호출하여 상태를 갱신합니다.ObjectManager::Render 함수void ObjectManager::Render(HDC hdc)
{
for (Object* object : _objects)
{
object->Render(hdc);
}
}
for (Object* object : _objects)
_objects에 저장된 모든 오브젝트를 순회합니다.object->Render(hdc);
Render 함수를 호출하여 화면에 렌더링합니다.ObjectManager::Clear 함수void ObjectManager::Clear()
{
for (Object* object : _objects)
{
delete object;
}
_objects.clear();
}
for (Object* object : _objects)
_objects에 저장된 모든 오브젝트를 순회합니다.delete object;
_objects.clear();
_objects 벡터를 비웁니다.ObjectManager, SceneManager, 또는 남은 세부 구현 중 더 필요한 부분이 있다면 알려주세요.
필요하다면 다른 클래스나 함수도 추가적으로 철저히 분석해 드리겠습니다.
ObjectManager와 SceneManager 클래스는 게임 오브젝트와 씬(Scene)을 관리하는 핵심적인 역할을 합니다. 아래에서 각각의 클래스와 관련된 모든 구현을 상세히 설명하겠습니다.
ObjectManager 클래스class ObjectManager
{
DECLARE_SINGLE(ObjectManager);
public:
void Init();
void Update();
void Render(HDC hdc);
void Clear();
template <typename T>
T* CreateObject();
void Add(Object* object);
void Remove(Object* object);
const vector<Object*>& GetObjects() const;
private:
vector<Object*> _objects;
};
DECLARE_SINGLE(ObjectManager)
ObjectManager를 싱글톤으로 선언합니다. ObjectManager 인스턴스만 존재하도록 보장합니다.void Init();
void Update();
void Render(HDC hdc);
void Clear();
template <typename T> T* CreateObject();
T는 생성할 오브젝트의 타입입니다.void Add(Object* object);
_objects 벡터에 추가합니다.void Remove(Object* object);
_objects 벡터에서 제거합니다.const vector<Object*>& GetObjects() const;
vector<Object*> _objects;
ObjectManager::Init 함수void ObjectManager::Init()
{
_objects.clear();
}
_objects.clear(); ObjectManager::Update 함수void ObjectManager::Update()
{
for (Object* object : _objects)
{
object->Update();
}
}
for (Object* object : _objects)
_objects에 저장된 모든 오브젝트를 순회합니다.object->Update();
ObjectManager::Render 함수void ObjectManager::Render(HDC hdc)
{
for (Object* object : _objects)
{
object->Render(hdc);
}
}
object->Render(hdc); ObjectManager::Clear 함수void ObjectManager::Clear()
{
for (Object* object : _objects)
{
delete object;
}
_objects.clear();
}
delete object;
_objects.clear();
_objects 리스트를 비웁니다.ObjectManager::Add 함수void ObjectManager::Add(Object* object)
{
_objects.push_back(object);
}
_objects.push_back(object); _objects 리스트에 추가합니다.ObjectManager::Remove 함수void ObjectManager::Remove(Object* object)
{
auto it = find(_objects.begin(), _objects.end(), object);
if (it != _objects.end())
{
delete *it;
_objects.erase(it);
}
}
auto it = find(_objects.begin(), _objects.end(), object);
_objects 리스트에서 제거할 오브젝트를 검색합니다.delete *it;
_objects.erase(it);
SceneManager 클래스class SceneManager
{
DECLARE_SINGLE(SceneManager);
public:
void Init();
void Update();
void Render(HDC hdc);
void Clear();
void ChangeScene(SceneType sceneType);
Scene* GetCurrentScene();
private:
Scene* _scene = nullptr;
SceneType _sceneType = SceneType::None;
};
DECLARE_SINGLE(SceneManager)
SceneManager를 싱글톤으로 선언합니다.void Init();
void Update();
void Render(HDC hdc);
void Clear();
void ChangeScene(SceneType sceneType);
Scene* GetCurrentScene();
Scene* _scene;
SceneType _sceneType;
SceneManager::Update 함수void SceneManager::Update()
{
if (_scene)
_scene->Update();
}
if (_scene)
_scene->Update();
Update 함수를 호출하여 상태를 갱신합니다.SceneManager::Render 함수void SceneManager::Render(HDC hdc)
{
if (_scene)
_scene->Render(hdc);
}
_scene->Render(hdc); Render 함수를 호출하여 화면에 렌더링합니다.SceneManager::ChangeScene 함수void SceneManager::ChangeScene(SceneType sceneType)
{
if (_sceneType == sceneType)
return;
SAFE_DELETE(_scene);
switch (sceneType)
{
case SceneType::MenuScene:
_scene = new MenuScene();
break;
case SceneType::FortressScene:
_scene = new FortressScene();
break;
}
_sceneType = sceneType;
if (_scene)
_scene->Init();
}
if (_sceneType == sceneType)
SAFE_DELETE(_scene);
switch (sceneType)
_scene->Init();
이제 ObjectManager와 SceneManager 클래스에 대한 설명이 완료되었습니다.
추가적으로 더 분석하거나 다뤄야 할 클래스나 함수가 있다면 알려주세요. 철저히 분석하여 설명드리겠습니다!