애니메이션 > 애니메이션 몽타주
사용할 스켈레톤 선택
AMWarriorAttack 몽타주 생성
PrimaryAttack 시리즈 애니메이션을 드래그해 배치하면, 링크되어 있으면 순차 재생된다.
창 > 애님 슬롯 매니저
슬롯 추가 > Attack
세팅 후 T-포즈가 보이면
기존 섹션 이름이 Default라서 헷갈릴 수 있다 → 섹션 이름을 바꾸면 정상 재생
추가 팁
Attack1~4 섹션 생성
섹션 링크 상태 확인
독립 재생하려면 섹션 링크를 끊는다
섹션 이름 가이드
특정 슬롯의 몽타주만 재생하도록 Slot 노드를 사용한다
DefaultSlot 개념
Slot에 재생 중인 몽타주가 없으면 Source 포즈가 그대로 통과한다
AnimGraph에 Attack 슬롯 배치
같은 경로 구조라면 보이는 변화는 없을 수 있다
개선 팁
AttackMontage 변수 선언
클래스 디폴트에서 AMWarriorAttack 할당
입력 처리 위치 예시(엔핸스드 인풋과 연동)
APlayerCharacter.h에 NormalAttack 가상함수
cpp 기본 구현
Warrior.h 오버라이드
Warrior.cpp 구현
APlayerCharacter.cpp NormalAttack 구현 확인
핵심 포인트
헤더에 PlayAttack 선언
cpp 정의
AnimInstance 유효 체크
Montage_Play, Montage_JumpToSection 사용
섹션 이름 배열 + 현재 인덱스
Attack Section Name 가시화
Attack1~4 이름 지정
배열에 이름이 잘 들어간 상태
PlayAttack에서 섹션 점프
샘플 코드
// PlayerDefaultAnimInstance.h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Attack")
TObjectPtr<UAnimMontage> AttackMontage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Attack")
TArray<FName> AttackSectionNames = { "Attack1","Attack2","Attack3","Attack4" };
int32 AttackIndex = 0;
UFUNCTION(BlueprintCallable) void PlayAttack();
UFUNCTION() void OnMontageEnded(UAnimMontage* Montage, bool bInterrupted);
// PlayerDefaultAnimInstance.cpp
void UPlayerDefaultAnimInstance::PlayAttack()
{
if (!AttackMontage || AttackSectionNames.Num() == 0) return;
if (!Montage_IsPlaying(AttackMontage))
{
Montage_Play(AttackMontage, 1.0f);
Montage_JumpToSection(AttackSectionNames[AttackIndex], AttackMontage);
FOnMontageEnded End;
End.BindUObject(this, &UPlayerDefaultAnimInstance::OnMontageEnded);
Montage_SetEndDelegate(End, AttackMontage);
}
}
void UPlayerDefaultAnimInstance::OnMontageEnded(UAnimMontage* Montage, bool bInterrupted)
{
if (!bInterrupted) AttackIndex = 0;
}
이동 중 전신 몽타주가 들어오면 부자연스럽다 → 지상에서만 허용
지상 체크 예시
void APlayerCharacter::NormalAttack()
{
if (GetCharacterMovement() && GetCharacterMovement()->IsMovingOnGround())
{
if (AnimInst) AnimInst->PlayAttack();
}
}
개선 팁
히트 타이밍과 콤보 전환 타이밍이 필요
애니메이션 더블클릭으로 타임라인 열기
공격판정 노티파이 Attack 생성
무기 스윙 위치에 충돌체 또는 트레이스 적용 권장
AttackCombo 노티파이도 각 섹션에 배치
몽타주 종료 콜백 함수 선언
cpp 정의
MontageEnd 호출 시점
Interrupted true/false 의미
AnimNotify 함수 선언
cpp 구현
노티파이 샘플
// PlayerDefaultAnimInstance.h
UFUNCTION() void AnimNotify_Attack(); // 히트 판정
UFUNCTION() void AnimNotify_AttackCombo(); // 콤보 인덱스 증가
// PlayerDefaultAnimInstance.cpp
void UPlayerDefaultAnimInstance::AnimNotify_Attack()
{
// 무기 소켓 경로로 짧은 스윙 트레이스 추천
// UKismetSystemLibrary::SphereTraceMultiForObjects(...) 등
}
void UPlayerDefaultAnimInstance::AnimNotify_AttackCombo()
{
AttackIndex = (AttackIndex + 1) % AttackSectionNames.Num();
}
고급 팁
Montage_SetNextSection으로 자연스럽게 이어줄 수 있다.기본 흐름
예시
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PlayerInputComponent))
{
EIC->BindAction(IA_Attack, ETriggerEvent::Started, this, &APlayerCharacter::Attackkey);
}
}
void APlayerCharacter::Attackkey(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Log, TEXT("Attackkey Enter"));
NormalAttack();
}
문제 상황 요약
Super::NormalAttack();를 호출하니 동작했고, 호출하지 않으면 동작하지 않았다.이유
NormalAttack()이 실제 재생 로직(mAnimInst->PlayAttack())을 가지고 있다.정리
권장 구조
체크리스트
성능/안정성
테스트 팁
한 개의 몽타주로 4콤보를 깔끔하게 관리하려면