AnimInstance 생성
캐릭터의 애니메이션을 관리하기 위해서 RPGAnimInstance를 상속받은 C++ 클래스를 생성해 주었습니다.
Animation Blueprint 생성
애니메이션 블루프린트를 만들기 위해서 스켈레톤을 지정 해주고
RPGAnimInstance를 기반으로 ABP_RPGCharacter 블루프린트를 만들어 줍니다.
AnimInstance는 애니메이션에 사용될 변수,함수를 관리하는 CPP 파일이고,
Animation Blueprint는 상속받은 애님 인스턴스와 애니메이션들을 이용해서
스켈레탈 메쉬를 의도에 맞게 움직이는 역할을 수행할 예정입니다.
static ConstructorHelpers::FClassFinder<UAnimInstance> AnimInstanceRef(TEXT("/Game/Character/ABP_RPGCharacter.ABP_RPGCharacter_C"));
if (AnimInstanceRef.Succeeded())
{
GetMesh()->SetAnimInstanceClass(AnimInstanceRef.Class);
}
또한 캐릭터의 생성자에 해당 코드를 작성하여 캐릭터가 방금 생성한 블루프린트를 가질수 있게 합니다.
클래스 정보이기 때문에 경로의 마지막에는 _C 를 넣어줬습니다.
C++ 코드 작성
RPGAnimInstance.h
protected:
virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
애니메이션 구성요소를 초기화 하기 위해 최초 생성시 호출하는 함수 NativeInitializeAnimation를 오버라이드하고,
캐릭터와 캐릭터의 움직임을 얻어오기 위해서 매 틱 마다 호출되는 NativeUpdateAnimation 함수를 오버라이드 해서 가져와 줍니다.
// 소유 캐릭터
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Character)
TObjectPtr<class ACharacter> Owner;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Character)
TObjectPtr<class UCharacterMovementComponent> Movement;
// 캐릭터 정보
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
FVector Velocity;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
float Speed;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
uint8 bIsIdle : 1;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
uint8 bIsInAir : 1;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
uint8 bIsJumping : 1;
애님 인스턴스를 소유하고 있는 캐릭터와 무브먼트을 불러와 저장할 수 있는 포인터와
캐릭터의 가속도, 속력, 가만히 서 있는지, 떨어지는 중인지, 점프하는 중인지 여부를 나타내기 위해서
여러 변수들을 선언 해주었습니다.
void URPGAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
Owner = Cast<ACharacter>(GetOwningActor());
if (Owner)
{
Movement = Owner->GetCharacterMovement();
}
}
오버라이드 해서 가져왔기 때문에 Super 키워드를 사용하여 부모 함수의 기능을 그대로 가져오고
AnimInstance를 소유하고 있는 캐릭터 오브젝트를 저장하기 위해 GetOwningActor함수를 이용해서 가져옵니다.
다만 액터 형식가 아닌 캐릭터 형식으로 저장해야 하기 때문에 형변환해 줍니다.
void URPGAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
if (Movement)
{
Velocity = Movement->Velocity;
Speed = Velocity.Size2D();
bIsIdle = Speed <= 0.f;
bIsInAir = Movement->IsFalling();
}
}
이 함수 역시 오버라이드 해서 가져왔기 때문에 Super키워드를 사용해 주고
캐릭터의 여러 정보를 지속적으로 변수에 업데이트해 줍니다.
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
이러한 함수의 기능 구현을 위해서는 다음과 같은 헤더파일이 필요합니다.
ABP_RPGCharacter의 애님 그래프
이동 구현
이동에 대한 애니메이션을 구현하기 위해 Ground Locomotion 이라는 이름의 스테이트 머신을 만들어 주고
다음과 같이 구성했습니다.
기본적으로 Idle -> JogStart -> Jog -> JogStop -> Idle 의 순서로 흐르게 됩니다.
다만 이동준비 모션 중 멈추게 되면 이동정지 모션을 재생해야 하고,
이동정지 모션 중 다시 움직이게 되면 Idle을 거치지 않고 바로 이동준비모션을 재생해야 어색하지 않기 때문에
두 애니메이션간의 흐름도 설정해 주었습니다.
JogStart -> Jog 와 JogStop - > Idle 의 조건에는 Automatic Rule을 적용하였습니다.
이는 애니메이션이 종료시 다음 애니메이션으로 자동으로 이동하게 되는 조건으로
이동준비가 끝나면 바로 이동모션, 이동정지 모션이 끝나면 바로 Idle로 가게 하도록 해줍니다.
Jog의 애니메이션은 이동키를 누를동안 계속해서 이동 애니메이션을 재생해야 하기 때문에
Loop 설정을해 줍니다.
Idle -> JogStar 와 Jog -> JogStop 은 bIsIdle 변수를 이용하여 조건을 판단합니다.
bIsIdle = Speed <= 0.f;
다음과 같은 코드를 계속해서 체크하여 캐릭터의 속력이 0 보다 커진다면 true를 나타내게 됩니다.
이를 이용해 true라면 JogStart를 수행하게 되고, 이동중에 false가 된다면 JogStop을 수행하게 될 것입니다.
점프/착지 구현
점프/착지 구현을 하기 전 우선 앞서 만든 이동 스테이트 머신을 캐시로 저장해 줍니다.
그리고 Locomotion 이라는 이름의 스테이트 머신을 새롭게 만들어 주었습니다.
IdleJog라는 이름의 스테이트를 만들어서 스테이트 내부에 앞서 만든 이동 스테이트 머신의 캐시를
Output과 연결하여 이동 스테이트 머신을 그대로 가져와 줍니다.
그리고 점프를 위한 스테이트 머신의 구성을 다음과 같이 구성 하였습니다.
bIsInAir변수가 true로 체크되면 Jump 스테이트를 진행합니다.
이후 bIsInAir이 false라면 Land 스테이트를 진행하고
오토매틱 룰으로 설정되어 Land 애니메이션이 끝나면 IdleJog로 돌아갑니다.
Jump 스테이트의 내부는 다음과 같이 되어 있습니다.
점프를 준비하고 점프후 낙하하는 과정까지 총 3개의 애니메이션으로 구성되어 순서대로 재생됩니다.
최종적으로 다음과 같은 모습을 하게 됩니다.
Ground Locomotion 스테이트 머신으로 이동 애니메이션을 구현하고 이를 캐시에 저장한 뒤
저장한 캐시를 기반으로한 스테이트 머신을 다시 만들어 점프 애니메이션을 구현해줍니다.
이를 다시 캐시에 저장하여 최종 Output Pose로 출력하게 합니다.
구현 결과 및 문제점
점프와 움직임 시 애니메이션을 구현했는데 문제점이 있었습니다.
1. 점프후 착지 모션때 움직이면 착지 모션인 상태로 움직인다
이 문제는 착지 모션중 점프키를 누르면 바로 다시 점프모션이 시작되게 해서 생긴 문제인데
점프사이 쿨타임을 적용하여 착지모션이 잠깐이라도 필수적으로 나오게 하면 어색한 문제가 해결될 것 같습니다.
2. 이동과 정지 시 미끄러지는 느낌이 난다
애니메이션이 의도한 이동속도와 캐릭터의 이동속도가 달라서 생기는 문제라고 추측하고 있습니다.
처음 움직이기 시작할때는 캐릭터가 느린 상태에서 점점 빠르게, 움직임이 끝났을 때에는 점점 느려지게 하도록
의도한 애니메이션이기 때문에 저는 애니메이션의 불필요한 부분을 트리밍하여 문제를 해결해보도록 하겠습니다.
감사합니다.
'[게임 개발] 개발 일지 > RPG' 카테고리의 다른 글
6. 캐릭터의 공격 애니메이션 구현 (0) | 2023.09.13 |
---|---|
5. 애니메이션 트리밍 및 문제점 수정 (0) | 2023.09.12 |
3. 향상된 입력을 이용한 캐릭터 이동 (0) | 2023.09.09 |
2. 카메라 설정 (0) | 2023.09.08 |
1. 게임 모드와 캐릭터 세팅 (0) | 2023.09.07 |