이득우의 언리얼 C++ 게임 개발의 정석을 읽고 개인 공부 목적으로 요약 정리한 글입니다!
: 다양한 상황에 적절한 애니메이션을 체계적으로 재생하도록 하는 애니메이션 시스템 제작 도구
애님그래프와 애님 인스턴스로 구성된다.
블루프린트의 기반을 이룬다.
Skeletal Mesh를 소유하는 Pawn의 정보를 받아 애님 그래프가 참조할 데이터를 제공
C++ / Blueprint 모두 가능
시각적 도구를 이용하여 애니메이션 시스템을 제작할 수 있다
애님 인스턴스의 변수 값에 따라 변화하는 애니메이션 시스템을 설계하는 공간
Blueprint에서만 제작 가능
class HUNT_PROTOTYPE_API UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true));
float CurrentPawnSpeed;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = ture));
bool IsInAir;
public:
UMyAnimInstance();
virtual void NativeUpdateAnimation(float DeltaTime) override;
};
UMyAnimInstance::UMyAnimInstance()
{
CurrentPawnSpeed = 0.0f;
IsInAir = false;
}
void UMyAnimInstance::NativeUpdateAnimation(float DeltaTime)
{
Super::NativeUpdateAnimation(DeltaTime);
APawn* Pawn = TryGetPawnOwner();
if (::IsValid(Pawn)) {
CurrentPawnSpeed = Pawn->GetVelocity().Size();
auto Character = Cast<ACharacter>(Pawn);
if (Character) {
IsInAir = Character->GetMovementComponent()->IsFalling();
}
}
}
IDLE / 달리기 / 점프 구현을 위해
CurrentPawnSpeed, IsInAir 변수를 선언하고
AnimInstance에서 Pawn의 정보를 받아와서 변수와 연동해준다.
🔥 Pawn에서 AnimInstance에 접근하면 안될까?
해도 괜찮긴 함. 멀쩡하게 동작함
But 애니메이션이 필요없는 서버 코드에서 문제가 발생할 수 있다
(애니메이션 로직과 폰의 로직의 분리가 어려움)
따라서 AnimInstance에서 Pawn을 접근하자.
Tick마다 호출되는 NativeUpdateAnimation() 함수 통해 연동해준다.
(AnimInstance 클래스에서 제공하는 가상함수)
TryGetPawnOwner() 함수를 통해 현재 폰을 받아오고, 정보를 연동한다.
🔥 언리얼 Tick 내부 로직 순서
사용자 입력 받아오기 -> 폰 움직이기 -> 애니메이션 재생
따라서 폰이 사라지면 애니메이션을 재생하면 안됨.
그래서 Pawn이 유효한지 항상 검사해줘야 한다
유한 상태 기계 방식.
스테이트(State) : 캐릭터가 반복해서 재생해야 할 애니메이션 동작
트랜지션 (Transition) : 각 State 사이를 이동하기 위한 조건
하나의 State만 지정해서 해당 State에서 지정한 동작을 수행하도록 한다.
점프할 때 점프 애니메이션을 띄우려면 플레이어가 점프중인지 알 수 있어야 한다.
어케아냐고?
Pawn의 MovementComponent가 함수들을 제공해준다.
물론,, 이걸 쓸 수 있는 컴포넌트는 Character Movement 컴포넌트 뿐이다 (당연함)
여기서 IsFalling() 함수를 통해 현재 Pawn이 점프중인지 정보를 받아와서 AnimInstance에 저장
그리고 그 값을 통해 애님 그래프에서 애니메이션을 재생한다.
위 사진이 점프를 구현한 상태의 스테이트 머신이다.
저기서 트랜지션을 보면,
이게 Ground -> JumpLoop.
현재 점프중이면 JumpLoop를 재생하고
JumpLoop에는
요렇게 점프 애니메이션을 넣는다.
마찬가지로
점프가 끝나면? (트랜지션 상 IsInAir == false)
JumpEnd에 착지하는 애니메이션을 넣어준다.
근데 얘네들은 계속 루프돌면서 재생되면 안되고, 한 번만 재생되어야 하므로
여기서 현재 체크되어 있는 애니메이션 루프 를 선택 해제 해준다.
그리구,
점프를 착지했으면 다시 Ground 애니메이션으로 돌아와야 한다.
조건 : 착지 애니메이션 재생이 끝났을 때.
이걸 쉽게 해줄 수 있는 옵션이 있다
스테이트의 시퀀스 플레이어에 따른 자동 규칙
(Automatic Rule Based on Sequence Player in State)
옵션을 체크하면,
애니메이션 종료 시 자동으로 스테이트가 전환된다.
끝!
괜찮쥬?
😊 느낀점
사실 애니메이션,, 진짜 어려운 느낌이었다
전에 혼자 유튜브보면서 해볼때,, 엄청 애먹었다 특히 점프할 때
근데 확실히 책을 보면서 따라가니까 이해가 잘 됐다!