이번에는 몬스터와 관련된 모든 클래스들에 대해 알아보자.
전체 소스코드 : https://github.com/vfly1189/TBI
아키텍처 구조
1. CMonFactory (Factory Pattern)
역할: 다양한 타입의 몬스터 객체를 생성하는 팩토리 클래스
주요 특징:
- 정적 팩토리 메서드: CreateMonster() 메서드로 통합된 몬스터 생성 인터페이스 제공
- 타입별 전용 생성 함수: 각 몬스터 타입별로 특화된 생성 로직 분리
- 헬퍼 메서드: 공통 초기화 작업을 담당하는 유틸리티 함수들
// 메인 팩토리 메서드
static CMonster* CreateMonster(MON_TYPE _eType, Vec2 _vPos, Vec2 _vGridPos, int option = 0);
// 타입별 전용 생성 함수
static CMonster* CreateFlyMonster(Vec2 _vPos, Vec2 _vGridPos, int option);
static CMonster* CreateHorfMonster(Vec2 _vPos, Vec2 _vGridPos);
static CMonster* CreateBabyPlumMonster(Vec2 _vPos, Vec2 _vGridPos);
2. AI 시스템 (State Pattern)
역할: 몬스터의 행동을 상태별로 관리하는 AI 시스템
구성 요소:
- AI 클래스: 상태 관리자 역할
- CState 추상 클래스: 모든 상태의 베이스 클래스
- 구체적 상태 클래스들: 각 몬스터별 특화된 행동 상태들
class AI {
map<MON_STATE, CState*> m_mapstate; // 상태 저장소
CState* m_pCurState; // 현재 상태
CMonster* m_pOwner; // 소유자 몬스터
};
구현된 몬스터 타입
1. Fly 몬스터
특성:
- 빠른 이동 속성 (속도: 40.f)
- 높은 인식 범위 (99999.f)
- 옵션에 따른 다른 애니메이션 (일반/공격형)
상태: Idle → Trace → Dead
2. Horf 몬스터
특성:
- 고정형 몬스터 (속도: 0.f)
- 원거리 공격 (공격 범위: 800.f)
- 중간 인식 범위 (200.f)
상태: Idle → Attack → Dead
3. Baby Plum 보스
특성:
- 고체력 보스 몬스터 (HP: 1000)
- 다양한 공격 패턴 (회전, 바운스, 급강하)
- 복잡한 애니메이션 시스템
상태: Idle → Trace → Attack → Dead
핵심 설계 패턴
1. Factory Pattern 적용
CMonster* CMonFactory::CreateMonster(MON_TYPE _eType, Vec2 _vPos, Vec2 _vGridPos, int option)
{
switch (_eType) {
case MON_TYPE::FLY:
return CreateFlyMonster(_vPos, _vGridPos, option);
case MON_TYPE::HORF:
return CreateHorfMonster(_vPos, _vGridPos);
case MON_TYPE::BABY_PLUM:
return CreateBabyPlumMonster(_vPos, _vGridPos);
}
}
장점:
- 객체 생성 로직의 캡슐화
- 새로운 몬스터 타입 추가 시 확장성
- 클라이언트 코드와 구체적 클래스의 분리
2. State Pattern 적용
class CState {
virtual void update() = 0;
virtual void Enter() = 0;
virtual void Exit() = 0;
};
장점:
- 몬스터 행동의 모듈화
- 상태 전환 로직의 명확성
- 새로운 행동 패턴 추가 용이성
몬스터별 상태 분석
Baby Plum (보스 몬스터)
상태 다이어그램
IDLE → TRACE → ATTACK → IDLE
↓ ↓
DEAD ←────────← DEAD
주요 상태들
1. CBabyPlumTraceState (추적 상태)
void CBabyPlumTraceState::update() {
// HP 체크 및 게임오버 확인
if (GetMonster()->Getinfo().m_iCurHP <= 0) {
ChangeAIState(GetAI(), MON_STATE::DEAD);
return;
}
// 공격 타이밍 체크 (3초마다)
m_fAccTime += fDT;
if (m_fAccTime > m_fAttackDuration) {
ChangeAIState(GetAI(), MON_STATE::ATTACK);
return;
}
// 플레이어 추적 로직
Vec2 vMonDir = vPlayerPos - vMonsterPos;
vMonDir.Normalize();
vMonsterPos += vMonDir * pMonster->Getinfo().m_fSpeed * fDT;
}
2. CBabyPlumAttackState (공격 상태)
3가지 랜덤 공격 패턴을 구현:
enum class BABYPLUM_ATTACK_TYPE {
TAKE_DOWN, // 8방향 + 14방향 눈물 발사
SPIN, // 회전하며 12방향 눈물 발사
BACK_BOUNCE // 벽 튕기며 연속 눈물 발사
};
TAKE_DOWN 패턴 분석:
void CBabyPlumAttackState::CreateTakeDownTear() {
// 8방향 고속 눈물
for (int i = 0; i < 8; i++) {
float angle = i * (PI / 4);
Vec2 vDir = { cos(angle), sin(angle) };
// 400 속도로 발사
}
// 14방향 저속 눈물
for (int i = 0; i < 14; i++) {
float angle = i * (2 * PI / 14);
Vec2 vDir = { cos(angle), sin(angle) };
// 200 속도로 발사
}
}
BACK_BOUNCE 패턴의 정교한 구현:
void CBabyPlumAttackState::update() {
// 방향 변화 감지 및 애니메이션 변경
if (m_vPrevDir != vCurDir) {
// 8가지 방향 전환에 따른 애니메이션 매핑
if (m_vPrevDir == Vec2(1, -1) && vCurDir == Vec2(1, 1))
GetMonster()->GetAnimator()->Play(L"babyplum_attack_backbounce_back_left", true, 1);
// ... 8가지 케이스 처리
}
// 동적 속도 증가 (100 → 1200 over 7초)
float speed = 100.f + (1200.f - 100.f) * (m_fAccTime / 7.f);
if (speed > 1200.f) speed = 1200.f;
}
Horf 몬스터 (원거리 공격형)
CHorfAttackState 특징:
- 정적 포탑형 몬스터 (속도 0)
- 0.8초 쿨타임으로 정확한 타이밍 제어
- 플레이어 위치 예측 공격
void CHorfAttackState::CreateTear() {
// 플레이어 위치 기반 방향 계산
Vec2 tearDir = (CPlayerMgr::GetInstance()->GetPlayer()->GetPos() - m_vMonsterPos).Normalize();
// 몬스터 전용 눈물 생성
CTear* attackTear = new CTear(m_vMonsterPos, GetMonster()->Getinfo().m_fAttRange, true);
attackTear->SetDir(tearDir);
}
Fly 몬스터 (기본형)
단순하지만 효과적인 3단계 구조:
- CFlyIdleState: 대기
- CFlyTraceState: 추적
- CFlyDeadState: 사망
구현의 핵심 기법
1. 상태 전환 메커니즘
void AI::ChangeState(MON_STATE _eNextState) {
CState* pNextState = GetState(_eNextState);
assert(m_pCurState != pNextState); // 같은 상태 전환 방지
m_pCurState->Exit(); // 현재 상태 종료 처리
m_pCurState = pNextState; // 상태 변경
m_pCurState->Enter(); // 새 상태 진입 처리
}
2. Factory Pattern과의 결합
CMonster* CMonFactory::CreateBabyPlumMonster(Vec2 _vPos, Vec2 _vGridPos) {
// AI 시스템 구성
AI* pAI = new AI;
pAI->AddState(new CBabyPlumIdleState);
pAI->AddState(new CBabyPlumTraceState);
pAI->AddState(new CBabyPlumAttackState);
pAI->AddState(new CBabyPlumDeadState);
pAI->SetCurState(MON_STATE::IDLE);
pMon->SetAI(pAI);
}
3. 애니메이션과 상태의 동기화
void CBabyPlumTraceState::Enter() {
GetMonster()->GetAnimator()->PauseAllAnimations();
GetMonster()->GetAnimator()->Play(L"babyplum_idle", true, 1);
m_fAccTime = 0.f; // 타이머 초기화
}
코드 품질 분석
장점:
- 명확한 책임 분리: 각 클래스가 단일 책임을 가짐
- 확장성: 새로운 몬스터나 상태 추가가 용이
- 재사용성: 공통 기능의 함수화
- 가독성: 의미 있는 네이밍과 구조화
개선 가능 점:
- 예외 처리: assert 외의 런타임 예외 처리 강화
- 메모리 최적화: 스마트 포인터 도입 고려
어필 포인트
- 디자인 패턴 활용: Factory와 State 패턴의 실무적 적용
- 객체지향 설계: 캡슐화, 상속, 다형성의 적절한 활용
- 게임 개발 경험: 실제 게임 로직과 애니메이션 시스템 구현
- 코드 구조화: 유지보수성과 확장성을 고려한 설계
- C++ 숙련도: 현대적 C++ 기법과 메모리 관리 역량
'WinApi > TBI(더 바인딩 오브 아이작) 모작' 카테고리의 다른 글
[Win32API TBI 모작] 11. Scene & 전투 화면 (0) | 2025.06.02 |
---|---|
[Win32 API TBI 모작] 10. Scene & 메인메뉴 (0) | 2025.05.31 |
[Win32 API TBI 모작] 8. CCollider & CImage & CRigidBody (0) | 2025.05.30 |
[Win32 API TBI 모작] 7. Animator & Animation (0) | 2025.05.30 |
[Win32 API TBI 모작] 6. CObject & CPlayer (0) | 2025.05.30 |