이전 글에서는 무기 장착을 위한 WeaponComponent 구현을 정리하면서,
무기 자체와 무기 장착 관리를 분리한 내용을 정리했다.
이번에는 그 다음 단계로 CombatComponent를 구현한 내용을 정리해보려고 한다.
WeaponComponent가 “현재 어떤 무기를 들고 있는가”를 관리한다면,CombatComponent는 “현재 어떤 전투 행동을 할 수 있는가”를 판단하는 역할을 담당한다.
처음에는 근접 공격, 원거리 공격, 재장전, 회피 같은 전투 로직을
각각의 컴포넌트에서 바로 처리해도 되지 않을까 생각했다.
하지만 구현을 진행하다 보니 전투 행동에는 공통적으로 관리해야 하는 상태가 있었다.
공격 중인지
재장전 중인지
회피 중인지
피격 경직 상태인지
상호작용 중인지
사망 상태인지
이런 상태를 각각의 컴포넌트가 따로 판단하면 중복이 많아지고,
서로 다른 행동이 동시에 실행되는 문제가 생길 수 있다.
그래서 CombatComponent를 전투 행동의 관리자 역할로 두었다.
CombatComponent의 역할
CombatComponent는 실제 공격 판정이나 재장전 처리를 직접 수행하는 컴포넌트가 아니다.
실제 근접 공격은 MeleeCombatComponent, 원거리 공격과 재장전은 RangedCombatComponent가 담당한다.
CombatComponent는 그보다 상위에서 현재 상태를 확인하고, 행동을 시작할 수 있는지 판단한 뒤,
세부 컴포넌트에 실행을 요청하는 역할을 한다.
PlayerCharacter
- 입력만 전달
CombatComponent
- 현재 전투 상태 확인
- 행동 가능 여부 판단
- 스태미너와 공격력 확인
- 세부 전투 컴포넌트에 실행 요청
MeleeCombatComponent
- 근접 공격 실행
- 콤보 처리
- 공격 판정 처리
RangedCombatComponent
- 사격 실행
- 재장전 처리
즉, CombatComponent는 전투의 관리자 역할에 가깝다.
전투 행동 상태 나누기
전투 행동을 관리하기 위해 ECombatActionState를 만들었다.

현재는 기본 상태인 None을 기준으로 공격, 재장전, 회피, 피격 경직, 상호작용, 사망 상태를 구분했다.
전투 행동은 대부분 None 상태일 때만 시작할 수 있도록 했다.
예를 들어 이미 공격 중인데 재장전을 시작하거나, 회피 중인데 다시 공격을 시작하면 전투 흐름이 꼬일 수 있다.
그래서 새로운 행동을 시작하기 전에 현재 상태를 확인하도록 했다.
TrySetActionState와 ForceSetActionState
상태 전환은 크게 두 가지로 나누었다.
TrySetActionState
- 일반적인 행동 전환에 사용
- 현재 상태에서 전환 가능한지 검사한 뒤 변경
ForceSetActionState
- 외부 사건으로 강제로 상태가 바뀌어야 할 때 사용
- 피격, 사망 같은 상황에 사용
예를 들어 공격, 재장전, 회피 같은 입력 기반 행동은 TrySetActionState를 사용한다.
이 함수는 현재 상태에서 해당 행동으로 전환할 수 있는지 먼저 확인한다.
반면 피격이나 사망은 플레이어 입력으로 시작되는 행동이 아니고,
외부에서 데미지를 받거나 체력이 0이 되었을 때 발생하는 사건이다.
이런 경우에는 일반적인 행동 가능 여부와 관계없이 상태가 바뀌어야 하므로 ForceSetActionState를 사용하도록 했다.
이렇게 나누니 “플레이어가 시도하는 행동”과 “외부 사건으로 강제되는 상태 변화”를 구분할 수 있었다.
ClearActionState
행동이 끝났을 때는 상태를 다시 None으로 되돌려야 한다.
이를 위해 ClearActionState를 만들었다.
처음에는 단순히 현재 상태를 무조건 None으로 바꿔도 되지 않을까 생각했다.
하지만 이렇게 하면 예상하지 못한 상태까지 초기화할 수 있다.
예를 들어 공격이 끝났다고 해서 현재 상태를 무조건 None으로 바꾸면, 중간에 피격이나 사망 상태로 바뀐 경우 문제가 생길 수 있다.
그래서 ClearActionState는 기대한 상태일 때만 상태를 해제하도록 했다.
예시는 다음과 같다.
공격 종료
→ 현재 상태가 Attacking이면 None으로 변경
재장전 종료
→ 현재 상태가 Reloading이면 None으로 변경
이렇게 하면 다른 상태를 실수로 덮어쓰는 일을 줄일 수 있다.
컴포넌트 참조 구조
CombatComponent는 전투 행동을 판단하기 위해 여러 컴포넌트를 참조한다.
WeaponComponent
- 현재 장착된 무기 조회
StatComponent
- 공격력 조회
- 스태미너 확인 및 소모
MeleeCombatComponent
- 근접 공격 실행
RangedCombatComponent
- 사격과 재장전 실행
처음에는 MeleeCombatComponent나 RangedCombatComponent가 직접 StatComponent와 WeaponComponent를 찾아도 되지 않을까 생각했다.
하지만 그렇게 하면 세부 전투 컴포넌트마다 비슷한 참조가 반복된다.
MeleeCombatComponent
- WeaponComponent 참조
- StatComponent 참조
RangedCombatComponent
- WeaponComponent 참조
- StatComponent 참조
이런 구조는 기능이 늘어날수록 중복이 많아질 수 있다.
그래서 현재 구조에서는 CombatComponent가 중심에서 무기와 스탯을 확인하고,
세부 컴포넌트에는 필요한 값만 넘겨주는 방식으로 정리했다.
예를 들어 근접 공격을 실행할 때는 CombatComponent가 현재 근접 무기를 가져오고,
최종 공격력을 계산한 뒤 MeleeCombatComponent에 전달한다.
CombatComponent
→ 현재 근접 무기 조회
→ 공격력 조회
→ 스태미너 확인
→ MeleeCombatComponent에 공격 요청
이렇게 하면 세부 공격 컴포넌트는 실제 행동 실행에 더 집중할 수 있다.
근접 공격 요청 흐름
근접 공격은 약공격과 강공격이 있지만, 큰 흐름은 비슷하다.
근접 공격 요청 흐름은 다음과 같다.


코드에서는 약공격과 강공격의 공통 흐름을 하나의 함수로 묶고, 필요한 처리만 람다로 넘기는 방식으로 정리했다.
1. MeleeCombatComponent가 있는지 확인
2. WeaponComponent에서 현재 근접 무기를 가져온다
3. 현재 공격 중인지 확인한다
4. 콤보 입력이 가능한지 확인한다
5. 첫 공격이라면 Attacking 상태로 전환한다
6. 스태미너가 충분한지 확인한다
7. 실제 공격 실행을 요청한다
8. 공격 실행에 성공하면 스태미너를 소모한다
여기서 가장 중요했던 부분은 스태미너 소모 타이밍이었다.
스태미너 소모 타이밍 문제
처음에는 상태 전환이 성공하면 바로 스태미너를 소모하는 흐름으로 생각했지만 실제 구현 중 문제가 발생했다.
공격 상태로 바뀌고 스태미너까지 소모했는데, 이후 실제 근접 공격 실행이나 콤보 전환이 실패할 수 있었다.
이 경우 플레이어 입장에서는 공격이 나가지 않았는데 스태미너만 줄어드는 문제가 생긴다.
예를 들어 다음 공격 몽타주가 없거나, 현재 공격 몽타주가 이미 끝나버린 경우에 이런 상황이 발생했다.
상태 전환 성공
→ 스태미너 소모
→ 실제 공격 실행 실패
→ 공격은 안 나갔는데 스태미너만 줄어듦
그래서 순서를 바꾸었다.
현재는 실제 공격 실행이 성공한 뒤에 스태미너를 소모한다.
상태 검사
→ 무기 확인
→ 콤보 가능 여부 확인
→ 스태미너 사용 가능 여부 확인
→ 실제 공격 실행
→ 공격 실행 성공 시 스태미너 소모
이렇게 바꾸니 공격이나 콤보가 실패했는데 스태미너만 줄어드는 문제를 막을 수 있었다.
첫 공격 실패와 콤보 실패 구분
근접 공격을 처리하면서 또 하나 중요했던 부분은 첫 공격 실패와 콤보 실패를 구분하는 것이었다.
첫 공격은 아직 공격 상태가 아니기 때문에, 공격을 시도하면서 Attacking 상태로 전환한다.
그런데 첫 공격 실행에 실패하면 다시 상태를 되돌려야 한다.
첫 공격 시도
→ Attacking 상태로 전환
→ 실제 공격 실패
→ Attacking 상태 해제
반면 콤보 공격은 이미 공격 중인 상태에서 추가 입력으로 이어지는 공격이다.
이때 콤보 입력이 실패했다고 해서 Attacking 상태를 해제하면 안 된다.
아직 기존 공격이 진행 중이기 때문이다.
콤보 공격 시도
→ 이미 Attacking 상태
→ 콤보 전환 실패
→ 기존 공격은 계속 진행 중
→ Attacking 상태를 해제하면 안 됨
그래서 현재 공격 중인지 확인한 뒤, 첫 공격 실패일 때만 상태를 되돌리도록 했다.
이 부분을 구분하지 않으면 콤보 입력 실패 때문에 공격 상태가 풀려버리는 문제가 생길 수 있다.
원거리 공격과 재장전
원거리 공격도 CombatComponent에서 요청을 받는다.
다만 사격은 근접 공격과 조금 다르게 처리했다.
근접 공격은 애니메이션이 시작된 뒤, 특정 타이밍에 공격 판정이 발생한다.
하지만 사격은 애니메이션 시작과 거의 동시에 공격이 수행된다.
따라서 사격은 즉발 행동에 가깝다고 보고, 별도의 Attacking 상태로 전환하지 않았다.
사격 입력
→ 현재 전투 행동 가능 여부 확인
→ 현재 총기 조회
→ 공격력 조회
→ RangedCombatComponent에 사격 요청
반면 재장전은 시간이 걸리는 행동이다.
재장전 중에는 다른 행동을 막아야 하므로 Reloading 상태로 전환한다.
재장전 입력
→ Reloading 상태로 전환 가능한지 확인
→ RangedCombatComponent에 재장전 요청
→ 재장전 실패 시 Reloading 상태 해제
→ 재장전 종료 이벤트를 받으면 상태 해제
즉, 사격은 짧게 실행되는 행동이므로 행동 전환이 이루어지지 않고,
재장전은 행동 전환이 이루어지는 것으로 판단했다.
행동 종료를 Delegate로 받기
CombatComponent가 상태를 관리하려면, 세부 컴포넌트의 행동이 언제 끝났는지도 알아야 한다.
예를 들어 근접 공격이 끝나면 Attacking 상태를 해제해야 하고, 재장전이 끝나면 Reloading 상태를 해제해야 한다.
그래서 세부 컴포넌트는 자신의 행동이 끝났을 때 이벤트를 발생시키고, CombatComponent는 그 이벤트를 받아 상태를 정리하도록 했다.


각 컴포넌트의 종료 이벤트는 CombatComponent에서 바인딩하고, 이벤트가 호출되면 해당 상태만 해제한다.
MeleeCombatComponent
→ 공격 종료 시 OnAttackFinished 발생
RangedCombatComponent
→ 재장전 종료 시 OnReloadFinished 발생
CombatComponent
→ 이벤트를 받아 상태 해제
이렇게 하면 세부 컴포넌트가 CombatComponent의 상태를 직접 바꾸지 않아도 된다.
세부 컴포넌트는 자신의 행동이 끝났다는 사실만 알려주고, 상태 변경은 CombatComponent가 담당한다.
사망 상태 처리
사망 상태도 CombatComponent에서 처리하도록 했다.


StatComponent에서 사망 이벤트가 발생하면 CombatComponent가 이를 받아 전투 가능 상태를 false로 바꾸고, 상태를 Dead로 전환한다.
StatComponent
→ OnDead 발생
CombatComponent
→ 전투 비활성화
→ Dead 상태로 강제 전환
사망 상태가 되면 더 이상 다른 행동으로 전환되지 않도록 했다.
이렇게 하면 죽은 뒤 공격하거나 재장전하는 상황을 막을 수 있다.
이동 가능 여부 판단
CombatComponent에는 CanMove도 추가했다.
이 함수는 현재 상태에서 캐릭터가 이동할 수 있는지를 판단한다.
예를 들어 공격 중, 회피 중, 피격 경직 중, 사망 상태라면 이동을 막을 수 있다.
이동 가능
- 전투 가능 상태
- 공격 중이 아님
- 회피 중이 아님
- 피격 경직 상태가 아님
- 사망 상태가 아님
이렇게 이동 가능 여부도 전투 상태를 기준으로 판단하면, 캐릭터 쪽에서는 복잡한 전투 상태를 직접 몰라도 된다.
캐릭터는 CombatComponent에 현재 이동 가능한지만 물어보면 된다.
전체 흐름 정리
현재 전투 행동 흐름은 다음과 같이 정리할 수 있다.
PlayerCharacter
- 입력을 받음
CombatComponent
- 현재 상태 확인
- 무기 확인
- 스태미너와 공격력 확인
- 행동 가능 여부 판단
MeleeCombatComponent / RangedCombatComponent
- 실제 공격, 콤보, 사격, 재장전 실행
Delegate
- 행동 종료를 CombatComponent에 알림
CombatComponent
- 상태 해제
핵심은 판단과 실행을 분리하는 것이다.
CombatComponent는 어떤 행동을 할 수 있는지 판단하고,MeleeCombatComponent와 RangedCombatComponent는 실제 행동을 수행한다.
정리
이번에는 전투 행동의 중심 역할을 하는 CombatComponent를 구현했다.
CombatComponent의 핵심 역할은 다음과 같다.
CombatComponent
- 현재 전투 행동 상태 관리
- 행동 가능 여부 판단
- 무기와 스탯 컴포넌트 확인
- 근접 / 원거리 컴포넌트에 실행 요청
- 행동 종료 이벤트를 받아 상태 해제
- 사망, 피격, 상호작용 같은 외부 상태 변화 처리
이번 구조에서 중요한 점은 CombatComponent가 실제 공격을 직접 수행하지 않는다는 것이다.
근접 공격과 원거리 공격은 각각 MeleeCombatComponent, RangedCombatComponent가 수행하고,CombatComponent는 그 행동을 시작할 수 있는지 판단하고 상태를 관리한다.
짧게 정리하면 다음과 같다.
CombatComponent는 전투 행동을 직접 실행하는 컴포넌트가 아니라,
전투 상태를 관리하고 행동 실행을 조율하는 관리자 역할을 한다.
다음 글에서는 CombatComponent가 실행을 요청하는 실제 근접 전투 컴포넌트,MeleeCombatComponent를 구현한 내용을 정리해보려고 한다.
'언리얼 엔진 > 프로젝트' 카테고리의 다른 글
| [언리얼 엔진] 팀 프로젝트 기록 07 - MeleeCombatComponent로 근접 공격과 콤보 구현하기 (0) | 2026.05.20 |
|---|---|
| [언리얼 엔진] 팀 프로젝트 기록 05 - 무기 장착을 위한 WeaponComponent 구현 (0) | 2026.05.18 |
| [언리얼 엔진] 팀 프로젝트 기록 04 - 전투 컴포넌트 설계하기 (0) | 2026.05.15 |
| [언리얼 엔진] 팀 프로젝트 기록 03 - 변경된 방 구조에 맞춰 Room Flow 수정하기 (0) | 2026.05.13 |
| [언리얼 엔진] 팀 프로젝트 기록 02 - StatComponent로 전투 스탯 관리하기 (0) | 2026.05.11 |