[개발전반] Text기반 RPG게임 제작이후 KRP 및 후기

2026. 1. 7. 20:31·프로그래밍/개발일지

Keep (잘한 점)

  • 기능의 완결성: 코드는 의도한 대로 동작하며, 게임의 루프(Loop)가 끊기지 않고 순환하는 구조를 잘 구현했다.
  • 책임의 분리 시도: 최소한 BattleSystem과 ShopSystem, UIManager를 파일 단위로 분리하려고 노력했다.

Problem (문제점 - 코드 기반 구체화)

  • God Class (GameManager): GameManager가 모든 시스템의 포인터를 소유하고 관리하는 '신(God)' 객체가 되어버려, 유지보수 시 사이드 이펙트가 우려된다.
  • 하드코딩된 로직: BattleSystem::SpawnMonster의 switch문과 UseItem의 if (HP < 0.5) 같은 로직이 시스템 내부에 박혀 있어, 기획 데이터 변경 시 코드 수정이 불가피하다.
  • 확장성 부족: 새로운 게임 모드나 몬스터를 추가할 때마다 기존 코드를 뜯어고쳐야 하는 구조다. (OCP 위반)

Try (시도할 점 - 구체적 액션 아이템)

  • Factory 패턴 적용: BattleSystem::SpawnMonster의 switch문을 제거하고, 몬스터 생성을 전담하는 MonsterFactory 클래스를 만든다.
  • State 패턴 적용: GameManager의 switch(Mode_)를 제거하고, IGameState 인터페이스를 상속받은 BattleState, ShopState 클래스로 나누어 상태를 관리한다.
  • Component 패턴 도입: GameManager가 모든 것을 new 하는 대신, 필요한 시스템을 컴포넌트 형태로 부착하거나 의존성 주입(DI)을 받도록 구조를 변경한다.
  • 데이터 주도 설계(Data-Driven): 몬스터 스폰 확률이나 아이템 사용 조건(50%) 등을 코드에서 빼내어 XML/JSON 혹은 별도의 설정 테이블로 관리하도록 구상해본다.

 

스파게티 코드를 막는 설계 원칙 (Factory & State Pattern)

1. switch 문의 지옥

프로젝트를 진행하며 BattleSystem과 GameManager를 구현했다. 기능은 잘 돌아가지만, 코드를 다시 보니 확장성에 심각한 문제가 있음을 발견했다.

❌ 나쁜 코드 예시 (내 코드)

// BattleSystem.cpp - 몬스터가 추가될 때마다 이 함수를 수정해야 함 (OCP 위반)
void BattleSystem::SpawnMonster(bool isBoss) {
    switch (RandomUtil::GetRandomInt(1, 10)) {
    case 1: monster_ = new BenediktKiss(...); break;
    case 2: monster_ = new DominikYork(...); break;
    // ... 몬스터가 100마리면 case가 100개?
    }
}

이 방식은 OCP(Open-Closed Principle, 개방-폐쇄 원칙)를 위반한다. 기능을 확장(몬스터 추가)하려면 기존 코드(BattleSystem)를 수정(Open)해야 하기 때문이다.

2. 해결책 1) 팩토리 패턴 (Factory Pattern)

객체 생성을 전담하는 공장(Factory)을 만들어 BattleSystem이 구체적인 몬스터 클래스(BenediktKiss 등)를 모르게 해야 한다.

  • Before: BattleSystem이 직접 new Monster()를 호출.
  • After: BattleSystem은 MonsterFactory::CreateRandomMonster()만 호출.

이렇게 하면 BattleSystem은 전투 로직에만 집중할 수 있고(응집도 상승), 몬스터 종류가 늘어나도 Factory만 수정하면 된다.

3. 해결책 2) 상태 패턴 (State Pattern)

GameManager에서 게임의 흐름을 제어하기 위해 switch (Mode_)를 사용했다.

// GameManager.cpp
while (bCanGameRunning) {
    switch (Mode_) {
    case BATTLE_MODE: ... break;
    case SHOP_MODE: ... break;
    // 모드가 10개면 GameManager는 수천 줄이 된다.
    }
}

이것 역시 상태가 늘어날수록 GameManager가 비대해지는 원인이 된다. State 패턴을 적용하여 각 상태(BattleState, ShopState)를 클래스로 나누고, GameManager는 현재 상태의 Execute()만 호출하도록 변경해야 한다.

4. 결론 (Action Plan)

  • 응집도(Cohesion): BattleSystem에서 '보상'과 '생성' 로직을 분리하자.
  • 결합도(Coupling): GameManager가 모든 객체를 알 필요가 없도록 추상화하자.
  • SOLID: OCP를 지키기 위해 if-else나 switch 도배를 멈추고 다형성(Polymorphism)을 활용하자.

'프로그래밍 > 개발일지' 카테고리의 다른 글

[UnrealEngine] 멀티플레이어 디펜스 `SagoMagic` 프로젝트 KPT 회고  (0) 2026.04.24
[개발전반] Ureal Engine 5를 이용해 한 달동안 진행했던 팀프로젝트 TPS게임 개발 KRP  (0) 2026.03.05
[개발전반] Best Practice란?  (0) 2026.02.03
'프로그래밍/개발일지' 카테고리의 다른 글
  • [UnrealEngine] 멀티플레이어 디펜스 `SagoMagic` 프로젝트 KPT 회고
  • [개발전반] Ureal Engine 5를 이용해 한 달동안 진행했던 팀프로젝트 TPS게임 개발 KRP
  • [개발전반] Best Practice란?
hanong8
hanong8
hanong8 님의 블로그 입니다.
  • hanong8
    HaNong
    hanong8
  • 전체
    오늘
    어제
    • 분류 전체보기 (101) N
      • 프로그래밍 (98) N
        • Unreal Engine 5 (45)
        • C++ (22)
        • UML (2)
        • 자료구조 (2)
        • 알고리즘 (9)
        • 개발일지 (4)
        • DirectX11 (5)
        • Git (2)
        • 코드카타 (7) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
hanong8
[개발전반] Text기반 RPG게임 제작이후 KRP 및 후기
상단으로

티스토리툴바