C++와 Unreal Engine으로 3D 게임 개발

C++와 Unreal Engine으로 3D 게임 개발 3-4

jh009 2026. 6. 21. 20:13

3-4. 캐릭터 체력 및 점수 관리 시스템 구현하기

1. 캐릭터 체력 시스템 구현하기

 

캐릭터 클래스에 체력 변수 및 함수 선언

PlayerState를 쓰지 않는 이유

  • 주로 멀티플레이 환경에서 각 플레이어 간 데이터 동기화를 위해 사용
  • 싱글 플레이 게임에서는 동기화가 필요 없음

캐릭터 클래스에 체력 관리 로직 추가

싱글 플레이 환경을 가정하여, 플레이어 캐릭터를 담당하는 SpartaCharacter 클래스에 체력 관리용 변수를 선언

  • MaxHealth: 캐릭터의 최대 체력
  • Health: 캐릭터의 현재 체력
  • TakeDamage(): 데미지를 받았을 때 호출되는 함수, 내부에서 체력을 감소시키는 로직을 처리
  • AddHealth(): 아이템 등을 통해 체력을 회복할 때 호출하는 함수, 내부에서 체력을 회복
  • OnDeath(): 체력이 0 이하가 되었을 때 호출되는 사망 처리 함수

SpartaCharacter.h


데미지 및 회복 처리

 

AddHealth(float Amount)

  • 체력을 일정 양만큼 회복
  • FMath::Clamp를 통해 최대 체력을 초과하지 않도록 제한

TakeDamage(...)

  • 언리얼 엔진의 기본 데미지 시스템을 사용하는 대표적인 함수
  • DamageAmount: 데미지 값
  • ActualDamage: 캐릭터가 입는 데미지 값 (예시: 데미지 30 - 방어력 20 = 10)
  • EventInstigator: 데미지를 유발한 주체(Controller)
  • DamageCauser: 데미지를 직접 발생시킨 오브젝트(총알, 폭발물 등)
  • 반환값: 실제 적용된 데미지(기본 로직에서는 DamageAmount와 동일한 경우가 많지만, 게임 상황에 따라 감소 또는 증폭 등을 처리할 수도 있음)

OnDeath()

  • 체력이 0 이하로 떨어졌을 때 사망 로직을 처리하는 함수
  • 입력 비활성화, Ragdoll 적용, 사망 애니메이션 재생 등을 수행

SpartaCharacter.cpp


지뢰 아이템 데미지 함수 수정

MineItem 이 폭발할 때, 주변 액터에게 데미지를 주려면 UGameplayStatics::ApplyDamage 함수를 호출

해당 액터의 TakeDamage()가 실행되도록 하면 됨

 

ApplyDamage()

  1. 대상 Actor 가 존재하는지 확인
  2. 대상 액터의 TakeDamage() 함수를 호출
  3. DamageType 은 여러 가지 파생 클래스를 만들어 물리/화염/독 등 다양한 데미지 유형을 정의할 수 있음 (지금은 기본값 사용)

지뢰는 독립적으로 스폰된 뒤 폭발하므로 EventInstigator를 nullptr로 둡니다.

멀티플레이에서 “누가 지뢰를 설치했느냐” 를 추적하려면, 생성 시점에 Instigator 나 Controller 정보를 넣어줄 수도 있음

MineItem.cpp


힐링 아이템 체력 회복 함수 수정

HealingItem → 플레이어를 회복

AddHealth() 함수를 직접 호출해 체력을 증가

 

ActorHasTag("Player") 로 플레이어인지 판별하는 단순 로직

캐릭터를 구분하는 더 안전한 방법

(예: Cast<ASpartaCharacter>(Activator)) 을 쓰거나, Collision 채널을 이용하는 식으로도 바꿀 수 있음

HealingItem.cpp


2. 점수 관리 시스템 구현하기

GameMode와 GameState의 연계 이해

언리얼 엔진에서의 GameMode, GameState

→ 게임의 전역 정보를 유지, 필요할 경우 멀티플레이어 환경에서 해당 정보를 서버클라이언트 간에 동기화하는 역할

 

GameMode

  • 게임의 규칙을 정의하고 관리
  • 어떤 캐릭터를 스폰할지, 플레이어가 사망했을 때 어떻게 처리할지를 결정
  • 멀티플레이에서는 서버 전용으로 동작 (클라이언트에는 존재하지 않음)

GameState

  • 게임 플레이 전반에서 공유되어야 하는 전역 상태를 저장
  • GameState는 기본적으로 레벨당 1개가 존재
  • 전역 데이터 관리용으로 적합 (엔진 내부에서 데이터 동기화를 고려해 설계되었음)
  • 점수, 남은 시간, 현재 게임 단계(Phase), 스폰된 오브젝트의 총 개수 등을 저장
  • 멀티플레이에서는 서버가 관리하고, 클라이언트는 이를 자동으로 동기화 받아볼 수 있음

싱글 플레이에서의 GameState

전역적으로 공유해야 할 정보를 한 군데서 관리하면 유지보수가 더 편함

아이템 스폰 개수, 현재 게임 진행도 등과 같은 데이터를 GameState 에서 일괄 관리할 수 있기 때문임


GameState에 점수 데이터 및 함수 추가

전역 점수를 GameState 에 저장 후, 점수를 획득할 때마다 AddScore()를 호출하여 점수가 증가하도록 구현

 

GameStateBase - 싱글플레이, 복잡하지 않은 게임

GameState - 멀티플레이 

 

C++ Class → GameStateBase 선택 → 이름 설정 (SpartaGameStateBase)

SpartaGameState.h

 

  • Score: 현재 누적된 점수
  • AddScore(int32 Amount): 점수를 Amount만큼 증가, 최대 점수 제한, 점수 획득 사운드 재생 등을 추가할 수도 있음
  • GetScore(): 현 점수 반환, 블루프린트에서 UI를 만들 때도 이 함수를 이용해 쉽게 점수를 가져올 수 있음

SpartaGameState.cpp


GameMode와 GameState 연동

기존에 만들었던 GameMode 클래스에서 GameStateClass 멤버를 SpartaGameState로 설정

SpartaGameMode.cpp

 

SpartaGameStateBase에 대한 C++ 코드가 컴파일 → 언리얼 에디터에서 해당 클래스를 인식하게 됨

 

SpartaGameStateBase를 더 확장하거나 블루프린트 비주얼 스크립팅을 사용하기 위해,

C++ 클래스를 부모로 하는 블루프린트(BP_SpartaGameStateBase)를 만들어서 사용

 

Project Settings 적용

Edit → Project Settings → Maps & Modes → Default GameMode

SpartaGameModeBase 또는 그 블루프린트 클래스로 설정

 

Game State Class → BP_SpartaGameStateBase(또는 SpartaGameStateBase) 로 설정

→ 전역적으로 이 설정이 적용

 

World Settings에서 설정 (레벨별로 오버라이드 가능)


코인 아이템 점수 획득 함수 수정

GetWorld()->GetGameState<ASpartaGameStateBase>() 로 게임 스테이트를 가져오기

AddScore(PointValue) 함수를 호출해 점수를 올림

PointValue(int32) → 코인 아이템이 제공하는 점수량, ACoinItem의 멤버 변수로 관리

 

플레이어가 코인을 획득하면, 전역적으로 관리되는 GameState에서 점수가 증가

코인은 사라져서 한 번만 획득되도록 처리

CoinItem.cpp