1. AnimInstance란?
AnimInstance는 애니메이션을 만들기 위해 필요한 데이터들의 집합이라 볼 수 있다.
즉,
애니메이션에 필요한 데이터가
- 캐릭터 이동 속도
- 공중에 있는지 여부
- 죽었는지 여부
이 있다고 하면 AnimInstance에서 위 데이터들을 관리하고
애니메이션은 AnimInstance에서 데이터를 참조해 최종 애니메이션을 재생한다.
그래서 애니메이션 블루프린트를 생성하려고 하면 부모 클래스는 AnimInstance가 되는 것을 볼 수 있다.
2. AnimInstance 코드 생성
블루프린트로 작업할수도 있지만 CPP로 하면 초기 상태나 변수 상태를 코드로 조작할 수 있기에 CPP로 생성한다.
2-1. 부모 클래스 선택
부모 클래스는 AnimInstance를 선택하자!
2-2. 변수 및 메서드 선언
애니메이션을 만들 때 필요한 정보는 일단 아래와 같이 정리할 수 있을 것 같다.
- 애니메이션 블루프린트를 소유하고 있는 Pawn 객체 변수
- 움직이는 속도
- 움직이는 방향
- 공중에 있는지 여부
코드로 변환하면 아래와 같다.
1
2
3
4
5
6
7
8
9
10
11
UPROPERTY(EditAnyWhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
float _movementSpeed;
UPROPERTY(EditAnyWhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
float _direction;
UPROPERTY(VisibleAnywhere, meta = (AllowPrivateAccess = "true"))
bool _bIsInAir;
UPROPERTY(EditAnyWhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
class APawn* _playerPawn;
그리고
3개의 멤버 변수 값들을 애니메이션이 진행되는 동안 계속 갱신될 수 있도록 UpdateProperties() 라는 변수를 만들어줄 것이다.
1
2
UFUNCTION(BlueprintCallable, Category = "Update Properties")
void UpdateProperties();
애니메이션 업데이트 될 때마다 UpdateProperties()를 호출할 수 있도록 NativeUpdateAnimation(float DeltaSeconds) 가상 함수를 오버라이드 한다.
1
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
마지막으로
애니메이션 블루프린트가 시작할 때 변수들을 초기화하고 싶기 때문에 NativeInitializeAnimation() 가상 함수를 오버라이드할 것이다.
1
virtual void NativeInitializeAnimation() override;
2-3. NativeInitializeAnimation
코드를 추가로 작성하기 전에 NativeInitializeAnimation()에 대해 좀 더 알아보자.
아래 코드는 공식 문서에서 그리고 UAnimInstance class에 적힌 주석 글처럼
“애니메이션 각 단계에 대한 초기화를 재정의하는 함수”라고 볼 수 있을 것 같다.
액터의 InitializeComponent 또는 BeginPlay 메서드와 유사하다
UAnimInstance::NativeInitializeAnimation
1
2
3
4
5
// the below functions are the native overrides for each phase
// 번역: 아래 함수는 각 단계에 대한 기본 재정의입니다.
// Native initialization override point
// 번역: 기본 초기화 재정의 지점
virtual void NativeInitializeAnimation();
2-4. NativeUpdateAnimation
NativeUpdateAnimation(float DeltaSeconds) 메서드는 애니메이션이 업데이트 될 때마다 재정의해주는 것이라 볼 수 있다.
액터의 Tick(float DeltaTime) 메서드와 유사하다.
1
2
3
// Native update override point. It is usually a good idea to simply gather data in this step and
// for the bulk of the work to be done in NativeThreadSafeUpdateAnimation.
virtual void NativeUpdateAnimation(float DeltaSeconds);
2-4. CPP 구현
이제 메서드를 하나씩 구현해 보자.
일단 NativeInitializeAnimation() 먼저 구현해 보자.
TryGetPawnOwner()를 통해 해당 애니메이션 블루프린트를 소유한 Pawn 객체를 얻는다.
1
2
3
4
5
6
7
8
void UCharacterAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
if (_playerPawn == nullptr)
{
_playerPawn = TryGetPawnOwner(); // 소유자의 Pawn를 가져온다.
}
}
그다음 UpdateProperties()를 통해 변수들의 상태를 업데이트해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void UCharacterAnimInstance::UpdateProperties()
{
if (_playerPawn == nullptr)
_playerPawn = TryGetPawnOwner();
if (_playerPawn)
{
// 공중에 있는지
_bIsInAir = _playerPawn->GetMovementComponent()->IsFalling();
// Z축이 필요없기 때문에 Z는 0.f로 처리해서 속력를 구한다
FVector velocity = _playerPawn->GetVelocity();
velocity = FVector(velocity.X, velocity.Y, 0.f);
_movementSpeed = FVector(velocity.X, velocity.Y, 0.f).Size();
// AnimInstance에 있는 CalculateDriection() 메소드를 통해 방향을 구한다.
_direction = CalculateDirection(velocity, _playerPawn->GetActorRotation());
}
}
그리고 UpdateProperties()를 NativeUpdateAnimation(float DeltaSeconds)에서 호출해 매 업데이트마다 호출되도록 한다.
1
2
3
4
5
void UCharacterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
UpdateProperties();
}