컨텐츠 검색
[UE5] Enemy AI 원거리 공격을 위한 서버 데이터 기반 Projectile Manager 구현 - 2

2026. 6. 11. 21:47구현

구현 1단계: 서버에서 원거리 공격 발사 시점을 감지하고, 총구에서 직선 탄도를 생성·수명 관리하는 것

  1. 공격 Montage Notify마다 정확히 한 발 생성된다.
  2. 무기의 S_Muzzle에서 시작한다.
  3. AI Target을 향해 직선으로 이동한다.
  4. 서버 Manager가 Actor 없이 구조체 배열로 관리한다.
  5. 수명이 끝나면 제거된다.
  6. Debug Draw로 궤적을 확인할 수 있다.
// 구현 흐름
ProjectileTypes
- 원거리 공격 GA가 투사체 Manager에 전달하는 발사 요청 정보 구조체
- 서버에서 관리되는 투사체 런타임 상태 정보 구조체

ProjectileManagerComponent
- FireProjectile: 새로운 투사체를 서버 배열에 등록한다.
- TickComponent: 서버에서 활성 투사체를 이동시키고 수명이 끝난 투사체를 제거한다. DebugLine 그림.

RunGameState
- GameState에 ProjectileManagerComponent를 등록한다.

EnemyAIController
- Blackboard에 저장된 현재 공격 대상을 반환한다.

EnemyWeaponBase
- 무기의 Muzzle 소켓의 Transform을 반환한다.

GA_EnemyAttackRanger
- 공격 횟수에 맞게: 
몽타주 재생 후
MuzzleTransform 위치, Target 액터 위치, 공격 방향, 투사체 속도, 투사체 최대 수명 시간을 
ProjectileManagerComponent의 FireProjectile의 매개변수로 넣고 실행한다.

 

구현 2단계: 서버 투사체 충돌 판정

  • Sphere Sweep로 이동 구간 검사
  • 벽, 바닥, 플레이어에 충돌
  • 발사한 Enemy는 무시
  • 충돌 지점 Debug 표시
  • 충돌한 투사체 즉시 제거
// 구현 흐름
Custom Trace Channel 생성
- Default는 Ignore로 설정
- Preset 중 BlockAll, BlockAllDynamic, Character만 Block으로 처리

ProjectileType의 각 구조체 추가된 데이터 / 
GA_EnemyAttackRanger에서 발사 요청으로 전달될 추가 데이터
- 투사체 충돌 반지름
- 투사체 Trace Channel
- 투사체를 발사한 SourceActor

ProjectileManagerComponent
- 충돌 검사 로직 추가:
  - Trace로 움직이는 동선에 투사체의 현재 위치를 갱신시키며 
    플레이어, 벽, 바닥, 엄폐물 등에 Block된 경우 Hit 처리
  - 충돌되지 않은 경우, 최대 수명 시간에 도달하면 투사체 제거
// Sweep 충돌 검사 옵션
FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(NSProjectile), false);

// 투사체를 발사한 Enemy 자신은 충돌 검사에서 제외
if (AActor* SourceActor = Projectile.SourceActor.Get())
{
    QueryParams.AddIgnoredActor(SourceActor);
}

// 충돌 결과를 받을 구조체
FHitResult HitResult;

// Sweep 충돌 검사
const bool bHit = World->SweepSingleByChannel(
    HitResult,
    PreviousLocation,
    NextLocation,
    FQuat::Identity,
    Projectile.TraceChannel,
    FCollisionShape::MakeSphere(Projectile.Radius),
    QueryParams
);

 

구현 3단계: 충돌 대상에게 GAS Damage GameplayEffect 적용

  • 충돌 대상의 ASC 조회
  • 발사자와 대상의 팀 확인
  • HitResult를 Effect Context에 저장
  • 기존 GEC_DamageExecution을 사용하는 Damage Effect 적용
  • 벽 충돌에는 피해 없음
// 구현 흐름
ProjectileType의 각 구조체 추가된 데이터 / 
GA_EnemyAttackRanger에서 발사 요청으로 전달될 추가 데이터
- Damage가 담긴 GameplayEffect 정보

ProjectileManagerComponent
- SourceActor로부터 발사자, 충돌 정보 추출해 Damage GameplayEffect와 함께 
  FGameplayEffectSpecHandle 형태로 TargetASC에 전달
- 같은 팀일 때는 피해 적용 X

현재는 몬스터의 공격이 명중 시점의 데미지로 들어가게끔 되어 있다. 만약 몬스터의 데미지가 버프 혹은 디버프를 받는다면 이미 발사한 투사체도 데미지가 버프 혹은 디버프된다.

좀 더 정확한 시점을 위해서는 발사 시점에 데미지가 결정되어야 한다고 보지만, 현재 GEC_DamageExecution 이라는 하나의 데미지 계산 로직을 플레이어와 몬스터가 공유하고 있었기에 섣불리 수정할 수 없다.

또한 몬스터에게 버프/디버프를 적용할지 말지에 대한 여부도 결정되지 않았기에 이에 대한 처리는 지금 할 것이 아니라고 생각이 들어 후순위로 미뤘다.

TODO:
몬스터 공격력 변경 또는 Pool 재사용이 도입되면
발사 시점 Damage Snapshot을 투사체 전용 경로로 구현한다.
공용 GEC_DamageExecution 변경 전 플레이어 공격 회귀 테스트 필요.

구현 4단계: Client RPC로 시각 투사체 Actor 로컬 생성

내용 정리 중...