1. EditScene 생성 및 기본 구조

강의에서는 EditScene이라는 도구(Scene)를 만들어 그림을 그리고 저장/로드하는 기능을 추가하고 있습니다. EditScene은 선을 그리고 이를 저장하여 Unit.txt라는 파일로 관리하며, 데이터를 중앙에 정렬하는 로직을 포함하고 있습니다.


코드 분석: Enums.h

#pragma once
enum class SceneType
{
    None,        // 기본값으로 아무런 Scene도 설정되지 않은 상태
    DevScene,    // 개발/테스트용 Scene
    GameScene,   // 실제 게임 플레이에서 사용하는 Scene
    EditScene    // 그림을 그리기 위한 도구로 사용되는 Scene
};

한 줄씩 설명

  1. #pragma once

    • 헤더 파일의 중복 포함을 방지하는 디렉티브입니다. 한 번만 포함되도록 보장합니다.
  2. enum class SceneType

    • 열거형 클래스입니다. SceneType은 가능한 Scene의 종류를 나열한 타입입니다. enum class를 사용하여 타입 안전성을 제공합니다.
  3. 열거형 값들:

    • None: 초기 상태나 기본값.
    • DevScene: 개발 중 테스트를 위한 Scene.
    • GameScene: 실제 게임 중에 사용할 Scene.
    • EditScene: 그림을 그리고 편집하는 Scene으로 이번 예제의 핵심입니다.

코드 분석: EditScene.h

#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 = {};               // 마지막 좌표 저장
};

한 줄씩 설명

  1. #pragma once

    • 중복 포함 방지.
  2. #include "Scene.h"

    • Scene 클래스의 정의를 포함하여 EditScene이 이를 상속할 수 있도록 합니다.
  3. class EditScene : public Scene

    • EditSceneScene 클래스를 상속합니다.
    • 즉, Scene의 공통 기능을 재사용하면서 EditScene 고유의 기능을 추가합니다.
  4. 생성자와 소멸자:

    • EditScene()
      • EditScene 객체를 초기화하는 생성자.
    • ~EditScene()
      • 객체가 소멸될 때 호출되는 소멸자. override를 사용하여 상위 클래스 소멸자를 명시적으로 재정의함.
  5. 가상 함수 (Virtual Functions):

    • Init()
      • Scene 초기화를 위한 함수. 실행 시 호출됩니다.
    • Update()
      • 매 프레임마다 호출되어 Scene의 동작을 업데이트합니다.
    • Render(HDC hdc)
      • Scene의 내용을 화면에 그리는 함수. HDC는 그리기에 사용되는 핸들입니다.
  6. 멤버 변수:

    • _lines:
      • vector<pair<POINT, POINT>> 타입으로, 선들의 시작점과 끝점을 저장합니다.
    • _setOrigin:
      • 새로운 선을 시작할 때 원점을 설정하는지 여부를 나타내는 불리언 값.
    • _lastPos:
      • 선의 마지막 위치를 저장하는 POINT 구조체.

코드 분석: EditScene.cpp

생성자 및 소멸자

EditScene::EditScene()
{
}

EditScene::~EditScene()
{
}
  1. EditScene 생성자

    • 아무런 초기화 코드가 없으므로 기본 상태에서 EditScene 객체가 생성됩니다.
  2. EditScene 소멸자

    • 특별한 메모리 해제가 필요하지 않아 비어 있습니다. (추후 메모리 관리를 추가할 수 있음)

Init 함수

void EditScene::Init()
{
}
  • 초기화 작업을 수행하기 위한 함수. 현재는 특별히 초기화할 내용이 없습니다.

Update 함수

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 상세 분석은 내용이 길어, 다음 메시지로 이어가겠습니다.

Update 함수 분석 (계속)


1. 마우스 입력 처리

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;
    }
}
  1. LeftMouse 버튼 눌림 확인

    • GET_SINGLE(InputManager)->GetButtonDown(KeyType::LeftMouse)는 왼쪽 마우스 클릭 여부를 확인합니다.
  2. 현재 마우스 위치 저장 (GetMousePos)

    • 현재 마우스 좌표를 POINT 구조체 형태로 반환합니다.
  3. _setOrigin 검사

    • true일 경우:
      • 첫 번째 클릭으로 원점을 설정합니다.
      • mousePos 값을 _lastPos에 저장하고 _setOriginfalse로 설정합니다.
    • false일 경우:
      • 현재 마우스 위치와 이전 위치(_lastPos)를 사용하여 선 정보를 _lines 벡터에 추가합니다.
      • 이후 _lastPos를 현재 마우스 위치로 업데이트합니다.

2. 오른쪽 마우스 클릭으로 초기화

if (GET_SINGLE(InputManager)->GetButtonDown(KeyType::RightMouse))
{
    _setOrigin = true;
}
  • 오른쪽 마우스 버튼이 눌리면 _setOrigintrue로 설정하여 다음 번 클릭 시 새 선의 시작점을 설정하도록 만듭니다.

3. 선 저장 기능 (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();
}
  1. wofstream 객체 생성 및 파일 열기

    • Unit.txt 파일을 쓰기 모드로 엽니다.
  2. 최소/최대값 초기화

    • minX, maxX, minY, maxY를 초기화합니다.
    • INT32_MAX, INT32_MIN은 각각 32비트 정수의 최댓값과 최솟값을 나타냅니다.
  3. 선의 범위 계산

    • _lines 벡터를 순회하며 각 선의 시작점과 끝점 좌표를 비교해 최소값과 최대값을 업데이트합니다.
  4. 중앙값 계산

    • midX = (maxX + minX) / 2, midY = (maxY + minY) / 2로 선의 중앙 좌표를 계산합니다.
  5. 라인 개수 저장

    • _lines의 크기를 파일 첫 번째 줄에 저장합니다.
  6. 포인트 좌표 저장

    • 각 선의 좌표를 중앙값으로 보정 후 (x1, y1)->(x2, y2) 형식으로 파일에 기록합니다.
  7. 파일 닫기

    • 파일 저장이 완료되면 file.close()로 파일을 닫습니다.

4. 선 로드 기능 (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();
}
  1. wifstream 객체 생성 및 파일 열기

    • Unit.txt 파일을 읽기 모드로 엽니다.
  2. 라인 개수 읽기

    • 첫 번째 줄에서 선의 개수를 읽어옵니다.
  3. 기존 데이터 초기화

    • _lines.clear()로 기존의 선 데이터를 모두 삭제합니다.
  4. 미리 정의된 중앙값

    • 화면 중심으로 좌표를 재배치하기 위해 midX = 400, midY = 300을 사용합니다.
  5. 포인트 데이터 읽기

    • ::swscanf_s를 사용하여 파일의 문자열 데이터를 좌표 값으로 변환합니다.
    • 좌표를 중앙값에 더해 화면 중앙에 배치되도록 보정합니다.
  6. 벡터에 선 추가

    • 읽은 좌표를 _lines 벡터에 추가합니다.
  7. 파일 닫기

    • 파일 읽기가 완료되면 file.close()로 파일을 닫습니다.

Render 함수

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);
    }
}
  1. _lines 순회

    • 저장된 모든 선 정보를 순회합니다.
  2. POINTPos로 변환

    • POINT 구조체를 Pos 객체로 변환합니다.
    • Pos는 사용자 정의 구조체로, float 타입의 x, y를 포함합니다.
  3. 선 그리기

    • Utils::DrawLine 함수를 호출하여 각 선을 화면에 그립니다.

profile
李家네_공부방

0개의 댓글