Unreal 개발 본 캠프 46일차

HappyCircle·2026년 2월 2일

Unreal 개발

목록 보기
63/163

📘 챌린지반 5일차 TIL

Unreal 공격 애니메이션 시스템 정리 (ABP / Montage / Notify / Slot / Mixamo + GAS 데미지)

오늘은 “공격 버튼을 눌렀을 때 애니메이션이 자연스럽게 재생되고, 정확한 타이밍에 데미지가 들어가게 만드는 구조”를 언리얼 애니메이션 시스템 관점에서 정리했다.
결국 핵심은 상태 기반(이동/점프) 은 ABP가 맡고, 이벤트 기반(공격/스킬) 은 Montage가 맡고, 타격 프레임 동기화는 Notify가 맡는 구조라는 것.

1) Unreal Animation System 구조: “레이어가 나뉘어야 편해진다”

언리얼 애니메이션은 “한 파일”이 아니라 여러 에셋/로직이 결합된 구조다.
역할을 나눠서 생각하면 확장(콤보/스킬/버프/디버프)이 쉬워진다.

요소 역할 오늘 연결된 포인트
Skeleton 뼈대 기준 (리타겟/공유 기준) Mixamo 애니메이션도 결국 Skeleton 기준으로 맞춰야 함
Animation Sequence 단일 클립 Punch 같은 원본 애니메이션
Animation Blueprint (ABP) “상태 기반 자동 재생” 로직 Idle/Walk/Run처럼 계속 평가되는 로직
State Machine 상태 전환 관리 Speed, InAir 같은 조건에 의해 전환
Montage “이벤트 기반 수동 재생” 공격/스킬 버튼 입력 시 실행
Slot ABP에 Montage 끼워 넣는 입구 Slot 없으면 Montage 재생 안 됨

2) Animation Blueprint vs Montage: “자동 vs 수동” 역할 분리

오늘 이해한 포인트는 이거였다:

ABP(State Machine) = “캐릭터 상태에 맞춰 자동으로 틀어주는 기본 애니메이션 엔진”

Montage = “플레이어 입력/이벤트로 순간적으로 끼어드는 액션 애니메이션”

왜 둘 다 필요할까?

이동은 계속 변하니까 매 프레임 “조건 평가”가 필요하고
공격/스킬은 버튼을 눌렀을 때 “한 번 실행”이 필요하다.

항목 Animation Blueprint Animation Montage
재생 방식 자동 (State Machine) 수동 (Play Montage)
대표 예시 Idle/Walk/Run/Jump Attack/Skill/Reload
트리거 속도/공중/상태 변수 입력/이벤트
중첩 기본적으로 한 상태만 Slot로 레이어 중첩 가능
제어 주체 ABP(조건) 코드/블루프린트(명령)

✅ 오늘 결론: Blueprint는 “상태 기반”, Montage는 “이벤트 기반”.

3) Slot System: “Montage가 들어갈 자리가 없으면 재생 자체가 안 된다”

오늘 실습에서 가장 중요한 함정 포인트:

ABP AnimGraph에 Slot 노드가 없으면 Montage는 재생되지 않는다.

구조를 그리면 이렇게 된다.

State Machine (Idle/Walk/Run)

Slot(DefaultSlot) ← 몽타주가 이 지점에서 들어와서 섞임

Output Pose

FullBody 공격이면 DefaultSlot

달리면서 상체 공격 같은 걸 하려면 UpperBodySlot 같은 식으로 분리 가능

오늘은 DefaultSlot만 사용해서 전신 공격을 구현.

4) AnimNotify: “타격 타이밍을 애니메이션 프레임에 묶는다”

가장 큰 깨달음은 이거였다:

공격 버튼 누르자마자 데미지 주면
애니메이션이랑 타이밍이 안 맞아서 “헛손질인데 데미지 들어감” 같은 이상한 느낌이 생긴다.

그래서 AnimNotify를 “타격 프레임”에 심어두고, 그 순간에 데미지를 적용한다.

AnimNotify vs AnimNotifyState
종류 타이밍 사용 예시
AnimNotify 한 순간 타격 판정, 발소리, 이펙트 트리거
AnimNotifyState 구간(시작~끝) 무적, 슈퍼아머, 히트박스 지속

오늘 실습은 AnimNotify(한 순간) 기반으로 데미지 적용.

5) Mixamo 활용 흐름: “무료 애니메이션 → Sequence → Montage”

Mixamo는 “애니메이션 라이브러리 + 리깅 포함”이라 실습 속도가 압도적으로 빠르다.

흐름

Mixamo에서 애니 다운로드

UE로 FBX import → Animation Sequence 생성

Sequence 우클릭 → Animation Montage 생성

ABP AnimGraph에서 Slot 확인

입력(IA_LMB) 바인딩 → Play Montage

6) 공격 시스템 구현 흐름 정리 (BP / C++)

BP 방식(핵심 개념만)

IA_LMB 입력 받으면

Play Montage(AM_Punch) 실행

➡️ 이건 애니메이션 “재생”까지만.

C++ 방식(핵심 코드 패턴)

헤더

UPROPERTY(EditDefaultsOnly, Category = "Combat")
TObjectPtr<UAnimMontage> AttackMontage;

UPROPERTY(EditDefaultsOnly, Category = "Input")
TObjectPtr<UInputAction> AttackAction;

void Attack();

바인딩 + 재생

void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent))
    {
        if (AttackAction)
        {
            EnhancedInput->BindAction(AttackAction, ETriggerEvent::Triggered, this, &AMyCharacter::Attack);
        }
    }
}

void AMyCharacter::Attack()
{
    if (AttackMontage)
    {
        PlayAnimMontage(AttackMontage);
    }
}

✅ 오늘 정리: 입력 → Montage 실행은 코드/블루프린트 어디서든 동일한 패턴.

7) Notify로 데미지 처리: “애니메이션 프레임에 데미지를 동기화”

오늘 구현은 “Custom AnimNotify”를 만들어서 Montage 타임라인 특정 프레임에서 실행되게 했다.

핵심 아이디어

타격 프레임에 AN_DealDamage를 놓는다

Notify가 호출되는 순간

전방 SphereTrace로 적 탐색

GAS ASC를 통해 GameplayEffect로 데미지 적용

8) Custom AnimNotify (C++) 구현 구조 요약

Notify 클래스 뼈대

UCLASS()
class MYPROJECT_API UAN_DealDamage : public UAnimNotify
{
    GENERATED_BODY()

public:
    virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
                        const FAnimNotifyEventReference& EventReference) override;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage")
    float TraceRadius = 50.f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage")
    float TraceStartDistance = 50.f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage")
    float TraceEndDistance = 150.f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage")
    TSubclassOf<UGameplayEffect> DamageEffectClass;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Debug")
    bool bShowDebug = false;
};

Notify 본체 로직 흐름(오늘 구현의 의미)

Owner(공격자) 가져오기

Forward 기준 Start/End 계산

SphereTrace로 맞은 대상들 찾기

공격자 ASC, 타겟 ASC 가져오기

GameplayEffectSpec 만들어서 적용

9) GameplayEffect 적용 패턴(자주 쓰는 “정석 루틴”)

이 부분은 오늘 “GAS 데미지 처리의 기본 뼈대”로 기억해둘 만하다.

FGameplayEffectContextHandle Context = ASC->MakeEffectContext();
Context.AddSourceObject(Attacker);

FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(EffectClass, Level, Context);

if (Spec.IsValid())
{
    ASC->ApplyGameplayEffectSpecToTarget(*Spec.Data.Get(), TargetASC);
}
profile
개발합시다!

0개의 댓글