NMEii
2026. 1. 30. 20:55
2026. 1. 30. 20:55
📅 오늘 공부 요약: 언리얼 C++ 3D 런 게임(Run Game) 개발
1. 프로젝트 개요
- 주제: 제한 시간 내에 코인을 수집하고 지뢰를 피해 목표 점수를 달성하는 3D 액션 게임
- 핵심 기술: 언리얼 게임플레이 프레임워크(GameMode, GameState, PlayerController, Character), 데이터 기반 스폰 시스템, 객체 지향적 아이템 설계
- 개발 환경: Unreal Engine 5, Visual Studio (C++)
2. 주요 구현 기능 및 로직 분석
A. 캐릭터 및 입력 시스템 (Enhanced Input)
- 이동 로직: Enhanced Input System을 도입하여 WASD 이동, 점프, 시선 처리(Look)를 구현함.
- 달리기(Sprint): Shift 키 입력 시 CharacterMovement->MaxWalkSpeed를 동적으로 변경하여 이동 속도 조절.
- 상태 관리: Health 변수를 관리하며, TakeDamage 함수 오버라이드(Override)를 통해 데미지 피격 시 체력 감소 및 사망 로그 출력.
- 구조: Camera와 SpringArm을 컴포넌트로 부착하여 3인칭 시점(TPS) 구축.
B. 게임 데이터 관리 (Game State & Instance)
- GameState의 역할: 게임의 규칙과 현재 상태를 총괄.
- 점수 관리: 획득한 점수를 GameInstance에 누적하여 레벨이 바뀌어도 점수 유지.
- 레벨 시스템: 코인을 모두 모으거나 시간이 종료되면 OpenLevel을 통해 다음 스테이지(Basic -> Advanced -> Boss)로 이동.
- 타이머: GetWorldTimerManager().SetTimer를 사용하여 제한 시간(LevelDuration) 카운트다운 구현.
- GameInstance: 레벨 전환 시에도 초기화되지 않는 데이터(TotalScore, CurrentLevelIndex)를 저장하는 영구 저장소로 활용.
C. 객체 지향적 아이템 시스템 (Polymorphism)
- 상속 구조: BaseItem을 부모 클래스로 두고, 기능별로 자식 클래스를 파생시켜 코드 재사용성을 높임.
- BaseItem (부모): 충돌 감지(OnOverlap) 및 ActivateItem 가상 함수 정의.
- CoinItem (자식): 점수 획득 로직 구현.
- HealingItem (자식): 체력 회복 로직 구현.
- MineItem (자식): 지뢰. 밟으면 즉시 터지지 않고 타이머 설정 후 일정 시간 뒤 폭발(Explode)하여 범위 데미지 적용.
- 설계 포인트: ActivateItem을 가상 함수(virtual)로 선언하여, 부모 포인터로 자식의 고유 기능을 호출하는 다형성 구현.
D. 데이터 기반 랜덤 스폰 (Weighted Random Spawn)
- SpawnVolume: 특정 박스 영역(BoxComponent) 내의 랜덤 좌표(GetRandomPointInVolume)에 아이템 생성.
- 가중치 랜덤 알고리즘:
- 단순 랜덤이 아닌, UDataTable에 정의된 확률(SpawnChance)을 기반으로 아이템 생성.
- 누적 확률(Cumulative Probability) 방식을 사용하여, 좋은 아이템은 적게, 함정 아이템은 많이 나오도록 기획 데이터 제어 가능.
- 로직: 전체 확률의 합(TotalChance) 내에서 랜덤 값을 뽑아, 누적값과 비교하여 어떤 아이템을 생성할지 결정.
E. UI 및 게임 모드 제어 (PlayerController)
- HUD 관리: 게임 중에는 시간, 점수, 레벨을 표시하는 위젯 출력.
- 메뉴 관리: 게임 시작 전이나 게임 오버 시 메인 메뉴 위젯 출력.
- 입력 모드 전환:
- 인게임: FInputModeGameOnly (마우스 숨김, 캐릭터 조작)
- 메뉴: FInputModeUIOnly (마우스 커서 표시, UI 조작)
3. 트러블 슈팅 및 배운 점 (Key Learnings)
⚠️ 문제 상황: 스폰된 액터의 정보 접근 불가
- 문제: GameState에서 생성된 코인의 개수를 세어야 하는데, SpawnVolume::SpawnRandomItem() 함수의 반환 타입이 void여서 생성된 액터 정보를 받아올 수 없었음.
- 해결: 반환 타입을 AActor*로 변경하고, GetWorld()->SpawnActor의 리턴값을 그대로 반환하도록 수정하여 GameState에서 IsA(ACoinItem::StaticClass())로 타입 체크가 가능하게 만듦.
💡 핵심 개념: 태그(Tag)와 형변환(Cast)
- 아이템이 플레이어와 충돌했는지 확인할 때 ActorHasTag("Player")를 사용함.
- 하지만 실제 로직(함수 호출)을 수행하기 위해서는 Cast<ASpartaCharacter>(OtherActor)를 통해 형변환이 필요함을 확인함. 태그는 단순 식별용, 캐스팅은 기능 접근용으로 구분하여 사용해야 함.
💡 핵심 개념: 델리게이트와 타이머
- 지뢰(MineItem) 구현 시 SetTimer를 사용하여 지연 폭발을 구현함. 즉시 발동하는 이벤트와 시간차를 두고 발생하는 이벤트를 구분하여 게임의 긴장감을 높이는 로직을 학습함.
4. 추후 개선 계획 (To-Do)
- 사망 처리 완성: 현재 로그만 출력되는 사망 로직을 수정하여, HP 0 시 게임 오버 UI 출력 및 조작 불능 상태로 전환.
- UI 바인딩: 현재 텍스트로만 표시되는 체력과 점수를 Progress Bar(체력바) 등 시각적 요소로 개선.
- 승리/패배 조건 분리: 시간 초과 시 무조건 다음 레벨로 가는 로직을 수정하여, '생존 시 승리' 또는 '코인 다 모을 시 승리' 등 명확한 규칙 확립.