애니메이션 몽타주란?
- 몽타주(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 |