본문 바로가기

게임프로그래밍/실습1

[언리얼 실습] 3. 캐릭터 애니메이션 적용하기

이제 믹사모에서 가져온 애니메이션을 상황에 맞게 적용하려고 한다.

 

이제부터 강의 내용이 잘 기억 나지 않아 강의를 다시 보면서 실습을 진행해보고자 한다.

 


목차

  1. 애니메이션 블루프린트 만들기
  2. C++ AnimInstance
  3. 상태에 따른 애니메이션 적용

1. 애니메이션 블루프린트 만들기

 

 

콘텐츠 브라우저에서 우클릭 →  애니메이션 → 애니메이션 블루프린트를 누른다.

 

 

다음과 같이 뜨면 우리가 사용했던 스켈레톤을 골라 생성을 하면 된다.

 

이때 내가 만든 캐릭터의 스켈레톤을 모르겠다면 캐릭터 블루프린트로 들어가 스켈레톤이 어떤 건지 확인하면 된다.

 

이제 애니메이션 블루프린트로 들어가보자

 

 

그럼 이러한 화면이 뜨며 이곳에서 애니메이션 설정을 할 수 있다.

 

이제 이동할때와 가만히 있을때의 애니메이션을 적용해야하는데 이때 기본적인 원리는 캐릭터의 현재 속도를 구하여 움직이고 있는지 아닌지를 판단하여 상황에 따른 적절한 애니메이션을 적용하는 것이다.

 

C++ 에서  캐릭터의 현재 속도를 알 수 있도록 해보자.


2. C++ AnimInstance

 

 

 

C++ 클래스 생성을 누르고 모든 클래스에 들어간 뒤 AnimInstance 를 입력하여 c++를 만든다.

 

 

이렇게 뭔가 많이 빈 화면이 나오게 된다. 이곳에서 코드를 짜서 캐릭터의 속도를 얻어 올 수 있도록 하겠다.

 

UCLASS()
class PRACTICE_API UKnightAnimInstance : public UAnimInstance
{
   GENERATED_BODY()

public:
   virtual void NativeInitializeAnimation() override;
   virtual void NativeUpdateAnimation(float DeltaTime) override
   
   UPROPERTY(BlueprintReadOnly)
   class AKnight* KnightCharacter;

   UPROPERTY(BlueprintReadOnly, Category = "Movement")
   class UCharacterMovementComponent* KnightCharacterMovement;

   UPROPERTY(BlueprintReadOnly, Category = "Movement")
   float GroundSpeed;
};

 

헤더 파일에 다음과 같이 함수를 선언한다.


virtual void NativeInitializeAnimation() override;

이 함수는 애니메이션 인스턴스가 처음 초기화 될 때 호출되는 함수이다.

 

virtual void NativeUpdateAnimation(float DeltaTime) override;

애니메이션 클래스에서 프레임마다 호출되는 함수이다.

 

class AKnight* KnightCharacter;

내가 만든 캐릭터를 담을 포인터

 

class UCharacterMovementComponent* KnightCharacterMovement;

캐릭터의 움직임을 담당하는 무브먼트 컴포넌트를 담을 포인터

 

float GroundSpeed;

캐릭터의 속도를 저장할 float 변수


이제 캐릭터 포인터와 무브먼트컴포넌트 포인터를 초기화 해보자

 

#include "KnightAnimInstance.h"
#include "Knight.h" // 캐릭터 헤더파일
#include "GameFramework/CharacterMovementComponent.h" // 무브먼트 컴포넌트 헤더파일

void UKnightAnimInstance::NativeInitializeAnimation()
{
	Super::NativeInitializeAnimation();

	KnightCharacter = Cast<AKnight>(TryGetPawnOwner());
	if (KnightCharacter)
	{
		KnightCharacterMovement = KnightCharacter->GetCharacterMovement();
	}

}

 

TryGetPawnOwner() 함수는 애니메이션 인스턴스가 현재 제어하고 있는 폰을 가져오는 함수이다. 캐릭터 클래스가 아닌 폰을 가져오기 때문에 Cast를 통해서 내 캐릭터에 맞는 타입으로 바꾸어주어야 한다.

 

캐릭터 클래스를 가져왔으면 GetCharacterMovement() 를 통해 무브먼트 컴포넌트를 가져와야한다.

이 함수를 쓰기 위해서 #include "GameFramework/CharacterMovementComponent.h" 가 필요하다.

 

이제 NativeUpdateAnimation() 함수를 정의해보자.

 

#include "Kismet/KismetMathLibrary.h" //UKismetMathLibrary 를 쓰기 위해 필요한 헤더 파일

void UKnightAnimInstance::NativeUpdateAnimation(float DeltaTime)
{
	Super::NativeUpdateAnimation(DeltaTime);

	if (KnightCharacterMovement)
	{
		GroundSpeed = UKismetMathLibrary::VSizeXY(KnightCharacterMovement->Velocity);
	}
}

 

캐릭터의 속도를 얻기 위해 VSizeXY() 함수를 사용한다. UKismetMathLibrary::VSizeXY() 함수는 백터의 X와 Y축 만을 이용하여 2D 백터의 크기를 구하는 함수라고 한다. 이를 통해 움직임이 있는지 없는지 알 수 있다.

 

이제 필요한 변수(GroundSpeed)를  얻는데 성공하였으니 이를 통해 캐릭터에 움직임에 맞는 애니메이션을 재생시켜보자.


3. 캐릭터 상태에 따른 애니메이션

 

다시 애니메이션 블루프린트로 돌아가 Anim graph에서 우클릭을 하고 State Machine을 가져오자.

 

 

그리고 현재는 아무런 의미가 없지만 일단 이렇게 연결해둔다. 그 다음 스테이트 머신을 더블 클릭해 안으로 들어가자

 

 

그런 다음 위와 같이 만들어 준다. 방법은 우클릭을 하고 Add state를 하면 된다.

 

idle과 run state를 더블클릭해서 들어가고 각각에 맞는 애니메이션을 연결해놓는다.

 

이제 이 두 상태를 전환할 수 있게 설정을 해야한다. 화살표 위쪽에 있는 동그라미를 눌러 안으로 들어간다.

 

 

다음 화면에서 C++에서 가져온 변수를 사용해야하는데 그러기 위해서는 톱니바퀴를 누르고

 

Show Inherited Variables를 체크해주어야 한다.

 

하지만 이렇게 해도 아무것도 안나온다. 왜냐하면 다른 설정을 안했기 때문이다. 우리가 만든 C++ 클래스를 적용시켜줘야한다.

 

 

상단에 클래스 세팅을 누른다. 그 다음 디테일 패널을 봐보자.

 

 

다음과 같이 뜨며 부모 클래스를 우리가 만든 c++ 인스턴스로 바꿔주면 된다.

 

 

그럼 이렇게 변수들이 아주 잘 나오는 것을 볼 수 있다.

 

다시 아까 화면으로 돌아가 설정을 해주자.

 

움직임이 있으면, 즉 Ground Speed가 0보다 크면 전환되게 규칙을 설정해주면 된다.

 

 

다음과 같이 간단하게 설정해줄 수 있다. 경고가 뜨는 것은 컴파일을 하면 사라진다.

 

반대로 돌아가는 것은 Ground Speed가 0과 같으면 된다.

 

 

애니메이션 블루프린트 설정은 다 끝났으니 이제 캐릭터 블루프린트로 돌아가자.

 

 

애니메이션 부분을 위와 같이 설정해주면 된다.

 

애니메이션이 잘 적용된 것을 볼 수 있다.

 

이제 다음은 점프 애니메이션을 집어 넣어보려고 한다. 그리고 현재 애니메이션이 어색하여 다른 애니메이션으로 대체하려고 한다.