- 메뉴바 토글. 이에 따른 윈도우 크기 조정 기능 구현.
// 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 |