본문 바로가기

Win32 api

Win32 api 강의 63화.

- 메뉴바 토글. 이에 따른 윈도우 크기 조정 기능 구현.

// CCore.h
...
class CCore
{
    SINGLETON(CCore)

private:
    ...
    // 메뉴바.
    HMENU m_hMenu;          // Tool Scene에서만 사용.
    ...

private:
    ...
    void clear_screen(HDC hDC);
    ...
    
public:
    ...
    void ToggleMenuBar(bool bMenu);
    void SetWindow(POINT ptResolution, Vector2 pos, bool bMenu);
};

 

Tool 씬에서만 메뉴바가 보이도록 수정하기 위해 Core 클래스에 메뉴바 토글 기능을 추가.

 

// CCore.cpp
...
CCore::~CCore()
{
    ...
    if (m_hMenu)
    {
        DestroyMenu(m_hMenu);
        m_hMenu = nullptr;
    }
}

int CCore::init(HWND _hWnd, POINT _ptResolution)
{
    m_hWnd = _hWnd;
    // 윈도우 조정.
    SetWindow(_ptResolution, Vector2(100.f, 100.f), false);

    // 메뉴바 생성.
    m_hMenu = LoadMenu(nullptr, MAKEINTRESOURCE(IDC_CLIENT));
    ...

 

메뉴바는 LoadMenu 를 통해 불러올 수 있음. 삭제할 때는 DestroyMenu 라는 또다른 함수로 없애주는 모양...

// CCore.cpp
...
void CCore::render()
{
    HDC hDCBack = m_pTexBackBuffer->GetDC();
    // 이전 화면 지우기
    clear_screen(hDCBack);

    CSceneMgr::GetInstance()->render(hDCBack);
    
...
void CCore::clear_screen(HDC hDC)
{
    SelectGDI sg(hDC, BRUSH_TYPE::BLACK);

    Rectangle(hDC
        , -1, -1, m_ptResolution.x + 1, m_ptResolution.y + 1);
}
...
void CCore::ToggleMenuBar(bool bMenu)
{
    SetWindow(m_ptResolution, Vector2(100.f, 100.f), bMenu);

    if (bMenu)
        SetMenu(m_hWnd, m_hMenu);
    else
        SetMenu(m_hWnd, nullptr);
}

void CCore::SetWindow(POINT ptResolution, Vector2 pos, bool bMenu)
{
    m_ptResolution = ptResolution;

    // 해상도에 맞게 윈도우 크기 조정.
    RECT rc = { 0,0,m_ptResolution.x,m_ptResolution.y };
    
    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, bMenu);
    
    SetWindowPos(m_hWnd, nullptr,
        static_cast<int>(pos.x), static_cast<int>(pos.y), // 윈도우 위치
        rc.right - rc.left, rc.bottom - rc.top, // 윈도우 크기 (해상도에 맞게 조정된 크기)
        0);
}

 

기존 코드를 함수로 묶은 것임. ToggleMenuBar 는 bool 입력값에 따라 메뉴바를 켰다껐다 하는 역할. 

// CScene_Tool.cpp
...
void CScene_Tool::Enter()
{
    // 메뉴바 부착.
    CCore::GetInstance()->ToggleMenuBar(true);
...
void CScene_Tool::Exit()
{
    // 메뉴바 제거.
    CCore::GetInstance()->ToggleMenuBar(false);
...

 

실행해보면 해상도는 유지된 채로, 메뉴바가 온/오프되기 때문에 윈도우 높이가 늘어났다 줄었다 하는 것을 확인.

 

- 몬스터 생성을 Factory 패턴으로.

// CMonsterFactory.h
...
enum class MONSTER_TYPE
{
    NORMAL,
    RANGE,

    END
};

class CMonsterFactory
{
public:
    static CMonster* CreateMonster(MONSTER_TYPE eType, Vector2 vPos);

public:
    CMonsterFactory() = delete;
    ~CMonsterFactory() = delete;
};

 

몬스터 생성을 전담하는 클래스. 디자인 패턴 중 하나인 Factory 패턴이다. 객체가 필요없기 때문에 생성자 + 소멸자를 없애줌.

static 함수만 사용함.

// CMonsterFactory.cpp
...
CMonster* CMonsterFactory::CreateMonster(MONSTER_TYPE eType, Vector2 vPos)
{
	CMonster* pMonster = nullptr;

	switch (eType)
	{
	case MONSTER_TYPE::NORMAL:
	{
		pMonster = new CMonster;
		pMonster->SetPos(vPos);
        pMonster->SetSize(Vector2(50.f, 50.f));

        // 콜라이더 생성.
        pMonster->CreateCollider();
        pMonster->GetCollider()->SetSize(pMonster->GetSize());
		pMonster->GetCollider()->SetOffsetPos(Vector2::zero);


        // 몬스터 정보 설정.
        tMonsterInfo info = {};
        info.fPatrolSpeed = 50.f;      // 초당 50 픽셀.
        info.fPatrolDistance = 100.f;  // 100 픽셀.
        info.fTraceSpeed = 80.f;       // 초당 80 픽셀.
        info.fTraceDistance = 200.f;   // 200 픽셀.
        pMonster->SetMonsterInfo(info);

		// AI 설정.
		AI* pAI = new AI();
		pAI->AddState(new CIdleState());
		pAI->AddState(new CPatrolState());
		pAI->AddState(new CTraceState());
		pAI->ChangeState(STATE_TYPE::IDLE);

		pMonster->SetAI(pAI);
	}
		break;
        ...

	return pMonster;
}

 

해당 함수에서 각종 세팅 값으로 몬스터를 초기화하고 생성해줌. 

// CScene_Start.cpp
...
void CScene_Start::Enter()
{
    for (int i = 0; i < 5; i++)
    {
        CMonster* pMonster = CMonsterFactory::CreateMonster
        (
            MONSTER_TYPE::NORMAL
            , Vector2(300.f + i * 60.f, 100.f)
        );
        if(pMonster == nullptr)
            continue;

        pMonster->SetName(L"Monster");

        CreateObject(pMonster, GROUP_TYPE::MONSTER);
    }
    ...

 

팩토리에서 생성되긴 했지만,

실제 오브젝트로서 관리되는 것은 CreateObject 전역 함수를 거쳐, Scene::AddObject 을 통해 Scene 에게 넘겨진 이후로

update, render 등이 호출될 수 있음. 즉 한 프레임이 끝나고 비로소 사용됨.

 

- 각 State에 대한 다형성 구현.

// CIdleState.cpp
...
void CIdleState::Update()
{
    ...
    float fDistance = Vector2::distance
    (
        pPlayer->GetPos()
        , pOwnerMonster->GetPos()
    );

    if(fDistance <= pOwnerMonster->GetInfo().fTraceDistance)
    {
        pAI->ChangeState(STATE_TYPE::TRACE);
        return;
    }
}
...
void CIdleState::Render(HDC hDC)
{
    CMonster* pOwnerMonster = GetOwner()->GetOwner();
    if (pOwnerMonster == nullptr)
        return;

    tMonsterInfo info = pOwnerMonster->GetInfo();

    Vector2 vRenderPos = WORLD2SCREEN(pOwnerMonster->GetPos());
    float fRadius = info.fTraceDistance;

    SelectGDI select(hDC, PEN_TYPE::RED);
    SelectGDI select2(hDC, BRUSH_TYPE::HOLLOW);
    Ellipse(hDC,
        static_cast<int>(vRenderPos.x - fRadius),
        static_cast<int>(vRenderPos.y - fRadius),
        static_cast<int>(vRenderPos.x + fRadius),
        static_cast<int>(vRenderPos.y + fRadius));
}

 

일단 간략하게나마 구현했다. 강의에서는 Collider, AI 같은 것들을 컴포넌트 방식으로 구현하지 않았다 보니 

확장성이 좀 떨어진다. 그래서 실험용으로만 사용함. 

 

Idle 상태에서는 Player 가 탐색 범위 안에 들어오면 Trace 상태로 전환하도록 하는 기능임.

Render 는 탐색 범위를 시각화하기 위해 임시로 만들어 보았다.

 

이렇게 빨간 원으로 Monster 들의 탐색 범위를 알 수 있음. 원래라면 이걸 Collider 로 구현하는 게 더 좋을 텐데, 강의 버전이므로 일단 넘어가자...

 

Trace 상태는 그냥 플레이어 방향으로 이동하는 거라 비슷한 원리므로 생략함.

'Win32 api' 카테고리의 다른 글

Win32 api 강의 66 - 76화.  (0) 2025.10.12
Win32 api 강의 64 - 65화.  (0) 2025.10.02
Win32 api 강의 62화.  (0) 2025.09.30
Win32 api 강의 59 - 61화.  (0) 2025.09.30
Win32 api 강의 57 - 58화.  (0) 2025.09.29