이번에는 전투화면을 담당하는 클래스 CScene_Fight에 대해 알아보자.
전체 소스코드 : https://github.com/vfly1189/TBI
화면 구성
🏗️ 클래스 구조 및 설계
주요 멤버 변수
// 렌더링 관리
Direct2DMgr* pD2DMgr;
// UI 패널들
CPanelUI* statPanel; // 스탯 표시 패널
CPanelUI* hpPanel; // 체력 UI 패널
CPanelUI* activeItemPanel; // 활성 아이템 패널
CPanelUI* pickUpItemPanel; // 획득 아이템 패널
CPanelUI* miniMapPanel; // 미니맵 패널
// 데이터 매핑 컨테이너
unordered_map<StatType, CSpriteUI*> m_mapStatTexts;
unordered_map<PickUpType, CSpriteUI*> m_mapPickUpText;
vector<CSpriteUI*> m_vecHearts;
// 상태 관리
PlayerStat m_stPrevPlayerStat; // 이전 프레임 플레이어 스탯
PickUp m_stPrevPickups; // 이전 프레임 픽업 아이템
bool m_bGameOver; // 게임 오버 상태
🎮 핵심 시스템 분석
1. 씬 생명주기 관리
Enter() - 씬 초기화
void CScene_Fight::Enter()
{
// 1. 해상도 및 기본 설정
Vec2 vResolution = CCore::GetInstance()->GetResolution();
Setup();
// 2. 맵 생성 및 오브젝트 배치
MapMgr::GetInstance()->MapGenerate();
// 3. 플레이어 설정
CPlayer* player = CPlayerMgr::GetInstance()->GetPlayer();
player->SetPos(Vec2(0.f, 0.f));
// 4. 충돌 시스템 설정
CCollisionMgr::GetInstance()->CheckGroup(GROUP_TYPE::PLAYER, GROUP_TYPE::ITEM);
// 5. UI 시스템 초기화
CreateStatUI();
CreateHpUI();
CreateActiveItemUI();
CreatePickUpUI();
CreateMiniMap();
CreateBossHpBar();
}
특징:
- 컴포넌트 기반 설계: UI, 충돌, 사운드 등 각 시스템이 독립적으로 관리
- 계층적 오브젝트 관리: 그룹별 오브젝트 분류 및 관리
2. 동적 UI 시스템
스탯 UI 생성 - 데이터 주도 설계
void CScene_Fight::CreateStatUI()
{
// 아이콘 분할 데이터 구조화
struct IconSplitData {
LPCWSTR name;
D2D1_POINT_2F start;
D2D1_POINT_2F end;
};
IconSplitData iconData[] = {
{L"stat_attack_icon", {0, 0}, {16, 16}},
{L"stat_move_speed_icon", {16, 0}, {32, 16}},
// ...
};
// UI 생성 파라미터 구조화
struct StatUIParams {
float yOffset;
LPCWSTR iconName;
float statValue;
bool isFirstPanel = false;
};
// 반복문을 통한 UI 생성
for (const auto& param : statParams) {
CPanelUI* statItem = statPanel->AddChild<CPanelUI>(Vec2(0.f, param.yOffset));
// UI 요소 생성 및 설정...
}
}
설계 패턴:
- 템플릿 메서드 패턴: 공통 UI 생성 로직의 재사용
- 데이터 주도 설계: 구조체 배열을 통한 UI 파라미터 관리
- 컨테이너 매핑: unordered_map을 통한 UI 요소 빠른 접근
실시간 UI 업데이트 시스템
void CScene_Fight::UpdateStatUI()
{
// 업데이트 정보 배열화
StatUpdateInfo stats[] = {
{StatType::Attack, current.m_fAttackDmg, &m_stPrevPlayerStat.m_fAttackDmg, 1.0f},
// ...
};
for (auto& stat : stats) {
if (abs(stat.currentValue - *stat.prevValue) > FLT_EPSILON) {
auto it = m_mapStatTexts.find(stat.type);
if (it != m_mapStatTexts.end()) {
wchar_t buffer[20];
swprintf_s(buffer, L"%.2f", stat.currentValue * stat.multiplier);
it->second->GetTextUI()->SetText(buffer);
}
}
}
}
최적화 기법:
- 더티 체킹: 값 변경 시에만 UI 업데이트
- 부동소수점 비교: FLT_EPSILON 활용한 안전한 실수 비교
- 효율적 검색: unordered_map을 통한 O(1) UI 요소 접근
3. 동적 비트맵 생성 - 미니맵 시스템
void CScene_Fight::CreateMiniMapOriginal()
{
// 1. 동적 렌더 타겟 생성
ID2D1BitmapRenderTarget* pGridRenderTarget = nullptr;
HRESULT hr = pD2DMgr->GetRenderTarget()->CreateCompatibleRenderTarget(
D2D1::SizeF(cols * 18.f + 54.f * 2.f, rows * 16.f + 48.f * 2.f),
&pGridRenderTarget
);
// 2. 그리드 기반 이미지 합성
for (UINT y = 0; y < rows; ++y) {
for (UINT x = 0; x < cols; ++x) {
if (gridMap[y][x] == 0) continue;
// 셀 타입별 다른 이미지 렌더링
if (cellMaps[y][x]->IsChecked()) {
pGridRenderTarget->DrawBitmap(pCellImage2, destRect, ...);
} else {
pGridRenderTarget->DrawBitmap(pCellImage, destRect, ...);
}
}
}
// 3. 생성된 비트맵 저장
pD2DMgr->StoreCreateMap(pGridBitmap, L"minimap_grid");
}
기술적 하이라이트:
- 동적 텍스처 생성: 런타임에 맵 상태에 따른 미니맵 텍스처 생성
- Direct2D 활용: 하드웨어 가속 기반의 효율적인 비트맵 조작
- 메모리 관리: 자동 해제 및 재사용을 통한 메모리 최적화
4. 최적화된 렌더링 시스템
뷰포트 컬링 구현
void CScene_Fight::update()
{
Vec2 vLookAt = CCamera::GetInstance()->GetLookAt();
Vec2 vLookAtLT = vLookAt - Vec2(480.f, 270.f);
Vec2 vLookAtRB = vLookAt + Vec2(480.f, 270.f);
for (UINT typeIDX = 0; typeIDX < (UINT)GROUP_TYPE::END; typeIDX++) {
for (size_t objIDX = 0; objIDX < m_arrObj[typeIDX].size(); objIDX++) {
// 정적 오브젝트에 대한 뷰포트 컬링
if (typeIDX == (UINT)GROUP_TYPE::TILE ||
typeIDX == (UINT)GROUP_TYPE::WALL) {
Vec2 vPos = m_arrObj[typeIDX][objIDX]->GetFinalPos();
if ((vPos.x > vLookAtLT.x && vPos.x < vLookAtRB.x) &&
(vPos.y > vLookAtLT.y && vPos.y < vLookAtRB.y)) {
m_arrObj[typeIDX][objIDX]->update();
}
}
}
}
}
성능 최적화:
- 뷰포트 컬링: 화면에 보이는 오브젝트만 업데이트
- 오브젝트 타입별 분기: 정적/동적 오브젝트 구분 처리
🛠️ 사용된 디자인 패턴
1. 싱글톤 패턴
- Direct2DMgr, CPlayerMgr, MapMgr 등 전역 관리자 클래스들
2. 컴포넌트 패턴
- UI 요소들을 독립적인 컴포넌트로 구성
3. 옵저버 패턴
- 스탯 변경 시 UI 자동 업데이트
4. 팩토리 패턴
- UI 생성 함수들에서 타입별 객체 생성
5. 상태 패턴
- 게임 오버, 보스전 등 상태별 동작 분기
'WinApi > TBI(더 바인딩 오브 아이작) 모작' 카테고리의 다른 글
[Win32API TBI 모작] 13. 시연 영상 (0) | 2025.06.02 |
---|---|
[Win32API TBI 모작] 12. 아이템 (폭탄 & 픽업아이템) (1) | 2025.06.02 |
[Win32 API TBI 모작] 10. Scene & 메인메뉴 (0) | 2025.05.31 |
[Win32 API TBI 모작] 9. 몬스터 & State 패턴 (0) | 2025.05.30 |
[Win32 API TBI 모작] 8. CCollider & CImage & CRigidBody (0) | 2025.05.30 |