UE4의 Animation Montage를 이용하여 콤보 공격을 구현해보자.
Animation 과 Character는 Mixamo를 이용하였습니다.
하나의 Animation으로 되어 있는 콤보 공격 Animation을 사용하였습니다.
1. Animation Montage 란?
- Animation Montage를 사용하면 블루프린트 또는 C++ 코드를 통해 Animation Asset을 바로 제어할 수 있다.
- 여러 애니메이션 시퀀스를 하나의 에셋으로 합칠 수 있고, 여러 섹션으로 나누어 일부 또는 조합 재생이 가능하다.
- Montage 안에서 이벤트를 발생시켜 사운드 재생, 특정 함수 재생 등 다양한 작업을 할 수 있다.
2. Animation Montage 사용법
Animation Montage 생성
Anim Slot Manager
Animation Montage를 생성해보면 DefaultGroup.DefaultSlot 이란 이름으로 되어 있는데
이름을 바꾸기 위해선 Anim Slot Manger를 통해 바꿀 수 있다.
(만약 Anim Slot Manger 가 보이지 않는다면, 상단 탭 Window에서 활성화할 수 있다.)
Montage Sections
아래 창에서 우클릭을 통해 새로운 Montage Section을 만들 수 있다.
Montage Section 이란,
말 그대로 전체 Montage를 여러 섹션으로 나눌 수 있는 기능이라 볼 수 있는데
Section 이름을 통해 C++
이나 Blueprint
에서 Montage_JumpToSection 이란 메소드로 특정 섹션으로 이동할 수 있다.
Notify
Notify를 통해 애니메이션 도중 특정 지점에 이벤트가 발생하도록 구성할 수 있다.
공식 문서에 설명이 잘 적혀 있다. 자세한 건 공식 문서에서!!
3. 만들어보자!
어떻게 구현할까?
현재 적용된 애니메이션이 전체 콤보 공격이 들어가 있는 형태이므로 섹션을 굳이 나눌 필요가 없다고 생각했다.
그러므로, 각 공격 애니메이션이 끝나는 타이밍에 Notify를 설정해서
유저가 공격을 이어나갈 시 -> 애니메이션 계속 진행 유저가 공격을 중단할 시 -> 애니메이션 중단
으로 플래그를 나누어 Notify 때 둘 중 하나의 작업이 진행되도록 구현했다.
Animation Montage에 Animation 적용
Notify 적용
- 각 공격 애니메이션이 끝나는 지점에 Notify를 설정해주었다.
- 총 3번의 공격이 존재하고 마지막 공격은 Notify를 설정할 필요가 없기 때문에 앞의 두 번 공격에 대해서만 설정했다.
C++ 코드
Project Setting -> Engine-Input -> Action Mappings 에 LMB란 이름의 Mapping을 추가
마우스 왼쪽 클릭을 할 경우 공격 메소드가 실행될 수 있게 코드를 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAction(TEXT("LMB"),IE_Pressed,this, &APlayerCharacter::PressLMB);
}
void APlayerCharacter::PressLMB()
{
bPressLMB = true;
Attack();
}
- 공격 메소드(
Attack()
) 구현- Mesh -> AnimInstance 에 접근하여 Montage를 플레이해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void APlayerCharacter::Attack()
{
if(bAttacking)
{
// 연속 공격인지를 확인
bContinueAttack = true;
}
else
{
// 공격 중임을 알려준다.
bAttacking = true;
// 현재 Mesh에서 AnimInstance를 가져오고
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
// AnimInstance가 존재한다면,
if(AnimInstance)
{
// Montage를 플레이한다.
// CombatMeleeAnimMontage: 위에서 만든 Animation Montage를 가진 변수
AnimInstance->Montage_Play(CombatMeleeAnimMontage);
}
}
}
여기까지 구현을 하고 나면 애니메이션은 진행이 되지만, Notify설정이 되지 않아 애니메이션 전체가 재생된다.
Notify
에 연결할 C++ 코드 구현- Notify를
blueprint
에서 조작할 것이기 때문에C++
에서 만든 메소드를UFUNCTION(BlueprintCallable)
를 통해 가져온다. - 콤보 공격이 유효한지를 알아내기 위해
DoAttackCombo()
라는 메소드를 생성
- Notify를
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void APlayerCharacter::DoAttackCombo()
{
// 3번에서 bAttacking == true 일 때,
// 마우스 왼쪽 클릭을 하게 되면 bContinueAttack = true 가 되게 설정하였다.
// 유저가 마우스 왼쪽 클릭을 누르지 않았다면,
if(!bContinueAttack)
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if(AnimInstance)
{
// Montage 종료
// 1.f는 Montage 애니메이션 중에 Stop될 때
// 애니메이션이 끊기지 않고 자연스럽게 1초 동안 애니메이션 블랜딩이 되게 한다.
AnimInstance->Montage_Stop(1.f,CombatMeleeAnimMontage);
}
}
// 다음 Notify를 위해 false 설정
bContinueAttack = false;
}
Notify
설정
우측 설명이 잘 안보여서 아래에 작성했다
1
2
3
4
5
6
7
8
DoAttackCombo() 에서
Montage_Stop(1.f,CombatMeleeAnimMontage);를 했는데
1.f로 인해 블랜딩 도중 bAttacking이 false가 되버린다.
(이럴 경우, 블랜딩 도중 공격 중이 아님이 되버리기에 여러 문제가 발생할 수 있다. (EX. 블랜딩 도중 캐릭터가 움직여짐))
이를 방지하기 위해
Delay를 1초 주어 블랜딩이 끝난 후 bAttacking = false 가 되게 설정하였다.