[Part 2] 캐릭터 콤보 액션

2026. 10. 6. 12:44·Unreal

애니메이션 몽타주란?

  • 몽타주(Montage): 이미지 일부를 잘라내 한 화면에서 합성화 하는 기법
  • 애니메이션 클립을 잘라내고 합성한 후 이를 재생하는 애니메이션 기능
  • 애니메이션 클립을 모아둔 다수의 섹션으로 구성되어 있음
  • 섹션끼리 연동할 수 있으며, 스크립트를 통해 원하는 섹션으로 건너뛸 수 있음
  • 시퀀스를 배치해서 섹션 단위로 재생을 제어하는 에셋

콤보 공격 기획

  • 콤보 정보를 저장한 데이터 애셋 생성 (ComboData/ABA_ComboAction)
  • 각 콤보마다 입력을 테스트하는 프레임 지정 (ABA_ComboAction에서 Effective Frame Count 지정)
  • 테스트 프레임 전에 입력이 들어오면 다음 몽타주 섹션으로 이어서 재생
  • 테스트 프레임보다 입력이 늦으면 해당 섹션을 마저 플레이하고 종료

  • Anim Sequence에서 동작 프레임을 확인, 모션이 끝나는 17프레임을 DataAsset에 설정
  • 17 프레임 이내에 입력이 들어오면 사전입력 감지 되었다고 판단
  • 다음 콤보 애니메이션 몽타주로 건너뜀
  • 입력이 들어오지 않았다면 다음 몽타주로 넘어가지 않고 재생끝

콤보 공격 구현할 때 로직

1. Animation Montage 생성

AM_ComboAttack 명으로 몽타주 생성하여 각 동작의 시퀀스를 배치한 후

마지막 동작이 몇번 프레임에서 발생하는지 확인

2. 생성한 Montage를 Anim Blueprint의 AnimGraph에 연결

ABP_ABCharacter에서 Anim Graph로 가서 몽타주가 들어올 자리인 Slot DefaultSlot을 추가

3. 입력 Input Action 추가

눌렀을 때 (Pressed)만 입력 가능하게 함, Triggers에 추가

4. IA 를 추가하면 Input Mapping Context에 매핑 추가

input action을 추가했으면 매핑을 해주어야 함.

입력이 들어오려면 어떤 동작 할것인지

4. C++ 에서 ABCharacterPlayer에 공격 입력 액션 추가

ABCharacterPlayer.h

// 공격 입력 액션
UPROPERTY(VisibleAnywhere, Category = Input, BlueprintReadOnly)
TObjectPtr<UInputAction> AttackAction;

ABCharacterPlayer.cpp

// 각각 입력 받는 함수에서 아래 코드 추가

static ConstructorHelpers::FObjectFinder<UInputAction> AttackActionRef(
    TEXT("/Game/ArenaBattle/Input/Actions/IA_Attack.IA_Attack")
);

if (AttackActionRef.Succeeded())
{
    AttackAction = AttackActionRef.Object;
}


// 각각 입력 받는 함수에서 아래 코드 추가
EnhancedInputComponent->BindAction(
    AttackAction,
    ETriggerEvent::Triggered,
    this,
    &AABCharacterPlayer::Attack
);

공격 입력에 대응되어 실행할 함수를 설정함

5. Data Asset 생성

위에서 4개의 동작 시퀀스를 몽타주로 설정하여서, index 0~3까지 Effective Frame Count에 추가하였으며

Index[3] = -1.0 은 마지막 공격은 다음 콤보 연결 없음을 알림

5. ABCharacterBase.cpp 수정

ABCharacterBase.cpp

void AABCharacterBase::ProcessComboCommand()
{
    // 처음 공격 시작할 때.
    if (CurrentCombo == 0)
    {
        ComboActionBegin();
        return;
    }

    // 처음이 아닌 경우
    // 타이머 핸등의 유효성 여부로 다음 공격으로 분기를 결정
    if (ComboTimerHandle.IsValid()) {
        // 입력이 제대로 들어왔다고 판정
        bHasNextComboCommand = true;
    }
    else {
        bHasNextComboCommand = false;
    }
}

void AABCharacterBase::ComboActionBegin()
{
    // 현재 콤보 단계를 1로 설정
    CurrentCombo = 1;

    // 몽타주 재생
    // 몽타주 재생을 위해 애님 인스턴스 가져오기

    UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();

    if (AnimInstance) {
        // 몽타주 재생 속도
        const float AttackSpeedRate = 1.0f;

        // 몽타주 재생
        AnimInstance->Montage_Play(ComboAttackMontage, AttackSpeedRate);

        // 몽타주 종료 이벤트에 등록
        FOnMontageEnded OnMontageEnded;
        OnMontageEnded.BindUObject(this, &AABCharacterBase::ComboActionEnded);

        AnimInstance->Montage_SetEndDelegate(OnMontageEnded, ComboAttackMontage);

        // 공격 모션 중에는 이동하지 않도록 설정
        GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None);

        // 타이머 재사용을 위해 초기화
        ComboTimerHandle.Invalidate();

        // 타이머
        SetComboCheckTimer();
    }
}

void AABCharacterBase::ComboActionEnded(UAnimMontage* TargetMontage, bool bInterrupted)
{
    // 확인
    ensureAlways(CurrentCombo > 0);

    // 콤보 단계 초기화
    CurrentCombo = 0;

    // 몽타주 재생이 종료되면 캐릭터 이동 복구
    GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking);
}

void AABCharacterBase::SetComboCheckTimer()
{
    // 현재 재생중인 콤보 단계의 인덱스 계산
    const int32 ComboIndex = CurrentCombo - 1;

    // 인덱스 값 확인
    ensureAlways(
        ComboActionData->EffectiveFrameCount.IsValidIndex(ComboIndex)
    );
    // 애니메이션 재생 속도
    const float AttackSpeedRate = 1.0f;

    // 곰보 공격 입력 시간(초단위) 계산
    float ComboEffectTime = (ComboActionData->EffectiveFrameCount[ComboIndex] / ComboActionData->FrameRate / AttackSpeedRate);

    // 타이머 설정
    if (ComboEffectTime > 0) {
        GetWorld()->GetTimerManager().SetTimer(ComboTimerHandle, this, &AABCharacterBase::ComboCheck, ComboEffectTime, false);
    }
}

void AABCharacterBase::ComboCheck()
{
    // 타이머 재사용을 위해 초기화
    ComboTimerHandle.Invalidate();

    // 콤보 타이머 이전에 공격 입력이 제대로 들어왔는지 확인 (분기)
    if (bHasNextComboCommand) {
        // 몽타주 점프 처리를 위해 애님 인스턴스 가져오기
        UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
        if (AnimInstance) {
            // 다음 단계 콤보 설정
            // CurrentCombo + 1
            CurrentCombo = FMath::Clamp(CurrentCombo + 1, 1, ComboActionData->MaxComboCount); // 1~4 안의 값으로 고정되도록

            // 점프할 섹션 이름 구성
            FName NextSection = *FString::Printf(TEXT("%s%d"), *ComboActionData->MontageSectionNamePrefix, CurrentCombo);

            AnimInstance->Montage_JumpToSection(NextSection, ComboAttackMontage);

            SetComboCheckTimer();

            // 콤보 처리에 사용한 값 초기화
            bHasNextComboCommand = false;
        }
    }
}
저작자표시 (새창열림)

'Unreal' 카테고리의 다른 글

[Part 2] 캐릭터 스탯과 위젯  (0) 2026.10.07
언리얼 엔진 직렬화  (0) 2026.10.01
[Unreal Blueprint] 머티리얼 피격 효과  (0) 2026.09.23
[Unreal Blueprint] 공격  (0) 2026.09.21
[Unreal Blueprint] 카메라 매니저  (0) 2026.09.21
'Unreal' 카테고리의 다른 글
  • [Part 2] 캐릭터 스탯과 위젯
  • 언리얼 엔진 직렬화
  • [Unreal Blueprint] 머티리얼 피격 효과
  • [Unreal Blueprint] 공격
야챔
야챔
  • 야챔
    월월왈왈
    야챔
  • 전체
    오늘
    어제
    • 전체보기
      • 일지
      • C++
      • Unreal
      • 자료구조
      • 코테연습
      • 알고리즘
        • 백준
        • 프로그래머스
      • 기타
        • Python
        • JavaScript
        • C#
        • MySQL
        • Docker
        • Review
        • RP
        • -----
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    예제
    Level2
    메이커스 6기
    Review
    MySQL
    docker
    Git
    node.js
    level1
    unreal
    프로그래머스
    Python
    정렬
    알고리즘
    c#
    백준
    파이썬
    라이징 프로그래머 2기
    개념
    탐색
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
야챔
[Part 2] 캐릭터 콤보 액션
상단으로

티스토리툴바