강의에서는 EditScene이라는 도구(Scene)를 만들어 그림을 그리고 저장/로드하는 기능을 추가하고 있습니다. EditScene은 선을 그리고 이를 저장하여 Unit.txt라는 파일로 관리하며, 데이터를 중앙에 정렬하는 로직을 포함하고 있습니다.
#pragma once
enum class SceneType
{
None, // 기본값으로 아무런 Scene도 설정되지 않은 상태
DevScene, // 개발/테스트용 Scene
GameScene, // 실제 게임 플레이에서 사용하는 Scene
EditScene // 그림을 그리기 위한 도구로 사용되는 Scene
};
#pragma once
enum class SceneType
SceneType은 가능한 Scene의 종류를 나열한 타입입니다. enum class를 사용하여 타입 안전성을 제공합니다.열거형 값들:
None: 초기 상태나 기본값.DevScene: 개발 중 테스트를 위한 Scene.GameScene: 실제 게임 중에 사용할 Scene.EditScene: 그림을 그리고 편집하는 Scene으로 이번 예제의 핵심입니다.#pragma once
#include "Scene.h"
class EditScene : public Scene
{
public:
EditScene();
virtual ~EditScene() override;
virtual void Init() override;
virtual void Update() override;
virtual void Render(HDC hdc) override;
private:
vector<pair<POINT, POINT>> _lines; // 선 정보를 저장하는 벡터 (시작점, 끝점)
bool _setOrigin = true; // 새로운 선의 시작점을 설정하는지 여부
POINT _lastPos = {}; // 마지막 좌표 저장
};
#pragma once
#include "Scene.h"
Scene 클래스의 정의를 포함하여 EditScene이 이를 상속할 수 있도록 합니다.class EditScene : public Scene
EditScene은 Scene 클래스를 상속합니다. Scene의 공통 기능을 재사용하면서 EditScene 고유의 기능을 추가합니다.생성자와 소멸자:
EditScene() EditScene 객체를 초기화하는 생성자.~EditScene() override를 사용하여 상위 클래스 소멸자를 명시적으로 재정의함.가상 함수 (Virtual Functions):
Init() Update() Render(HDC hdc) HDC는 그리기에 사용되는 핸들입니다.멤버 변수:
_lines: vector<pair<POINT, POINT>> 타입으로, 선들의 시작점과 끝점을 저장합니다._setOrigin: _lastPos: POINT 구조체.EditScene::EditScene()
{
}
EditScene::~EditScene()
{
}
EditScene 생성자
EditScene 객체가 생성됩니다.EditScene 소멸자
void EditScene::Init()
{
}
void EditScene::Update()
{
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::LeftMouse))
{
POINT mousePos = GET_SINGLE(InputManager)->GetMousePos();
if (_setOrigin)
{
_lastPos = mousePos;
_setOrigin = false;
}
else
{
_lines.push_back(make_pair(_lastPos, mousePos));
_lastPos = mousePos;
}
}
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::RightMouse))
{
_setOrigin = true;
}
// Save
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::S))
{
wofstream file;
file.open(L"Unit.txt");
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();
}
// Load
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::D))
{
wifstream file;
file.open(L"Unit.txt");
int32 count;
file >> count;
_lines.clear();
int32 midX = 400;
int32 midY = 300;
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);
pt1.x += midX;
pt1.y += midY;
pt2.x += midX;
pt2.y += midY;
_lines.push_back(make_pair(pt1, pt2));
_setOrigin = true;
}
file.close();
}
}
Update 상세 분석은 내용이 길어, 다음 메시지로 이어가겠습니다.
if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::LeftMouse))
{
POINT mousePos = GET_SINGLE(InputManager)->GetMousePos();
if (_setOrigin)
{
_lastPos = mousePos;
_setOrigin = false;
}
else
{
_lines.push_back(make_pair(_lastPos, mousePos));
_lastPos = mousePos;
}
}
LeftMouse 버튼 눌림 확인
GET_SINGLE(InputManager)->GetButtonDown(KeyType::LeftMouse)는 왼쪽 마우스 클릭 여부를 확인합니다.현재 마우스 위치 저장 (GetMousePos)
POINT 구조체 형태로 반환합니다._setOrigin 검사
true일 경우:mousePos 값을 _lastPos에 저장하고 _setOrigin을 false로 설정합니다.false일 경우:_lastPos)를 사용하여 선 정보를 _lines 벡터에 추가합니다._lastPos를 현재 마우스 위치로 업데이트합니다.if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::RightMouse))
{
_setOrigin = true;
}
_setOrigin을 true로 설정하여 다음 번 클릭 시 새 선의 시작점을 설정하도록 만듭니다.if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::S))
{
wofstream file;
file.open(L"Unit.txt");
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 객체 생성 및 파일 열기
Unit.txt 파일을 쓰기 모드로 엽니다.최소/최대값 초기화
minX, maxX, minY, maxY를 초기화합니다.INT32_MAX, INT32_MIN은 각각 32비트 정수의 최댓값과 최솟값을 나타냅니다.선의 범위 계산
_lines 벡터를 순회하며 각 선의 시작점과 끝점 좌표를 비교해 최소값과 최대값을 업데이트합니다.중앙값 계산
midX = (maxX + minX) / 2, midY = (maxY + minY) / 2로 선의 중앙 좌표를 계산합니다.라인 개수 저장
_lines의 크기를 파일 첫 번째 줄에 저장합니다.포인트 좌표 저장
(x1, y1)->(x2, y2) 형식으로 파일에 기록합니다.파일 닫기
file.close()로 파일을 닫습니다.if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::D))
{
wifstream file;
file.open(L"Unit.txt");
int32 count;
file >> count;
_lines.clear();
int32 midX = 400;
int32 midY = 300;
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);
pt1.x += midX;
pt1.y += midY;
pt2.x += midX;
pt2.y += midY;
_lines.push_back(make_pair(pt1, pt2));
_setOrigin = true;
}
file.close();
}
wifstream 객체 생성 및 파일 열기
Unit.txt 파일을 읽기 모드로 엽니다.라인 개수 읽기
기존 데이터 초기화
_lines.clear()로 기존의 선 데이터를 모두 삭제합니다.미리 정의된 중앙값
midX = 400, midY = 300을 사용합니다.포인트 데이터 읽기
::swscanf_s를 사용하여 파일의 문자열 데이터를 좌표 값으로 변환합니다.벡터에 선 추가
_lines 벡터에 추가합니다.파일 닫기
file.close()로 파일을 닫습니다.void EditScene::Render(HDC hdc)
{
for (auto& line : _lines)
{
POINT pt1 = line.first;
POINT pt2 = line.second;
Pos pos1;
pos1.x = (float)pt1.x;
pos1.y = (float)pt1.y;
Pos pos2;
pos2.x = (float)pt2.x;
pos2.y = (float)pt2.y;
Utils::DrawLine(hdc, pos1, pos2);
}
}
_lines 순회
POINT를 Pos로 변환
POINT 구조체를 Pos 객체로 변환합니다. Pos는 사용자 정의 구조체로, float 타입의 x, y를 포함합니다.선 그리기
Utils::DrawLine 함수를 호출하여 각 선을 화면에 그립니다.