4강 캐릭터 애니메이션 설정
- 정리
- 캐릭터 애니메이션 생성과 설계
- C++클래스를 상속받은 애니메이션 블루프린트의 생성 방법의 이해
- 이벤트 그래프와 애님 그래프로 구성된 애니메이션 블루프린트의 구조 파악
- 애님 그래프를 사용한 애니메이션 시스템의 설계 방법의 학습
- 캐릭터 애니메이션 생성과 설계
- Skeletal Mesh Componet에 보면 애니메이션 모드가 Use Animation Blueprint로 설정되어 있다면, Anim Class로 등록되어 있는 클래스 정보를 캐릭터가 생성될 때 해당 클래스로부터 인스턴스를 생성해서 애니메이션을 담당하는 인스턴스 언리얼 오브젝트를 생성해서 관리를 시키도록 일임한다.
- 이러한 애니메이션 블루프린트 시스템이 전체적인 캐릭터 모션을 담당한다고 이해하면 된다.
- C++로 AnimInstace 클래스를 직접 만들고 애니메이션 블루프린트가 우리가 생성한 C++ 클래스를 상속받아서 기본적인 로직을 구현한 후에 AnimGraph를 사용하여 구체적인 모션을 지정하도록 설계
- 이 후 애니메이션 블루프린트를 생성한다.
- 애니메이션 블루프린트를 생성할 때 사용할 스켈레톤 메쉬를 선택하고 방금 만든 ABAnimInstance (AnimInstance C++클래스)를 Parent Class로 설정해준다.
// 메쉬 지정
// 적용하고 싶은 스켈레탈 메쉬의 Copy Reference 복붙
static ConstructorHelpers::FObjectFinder<USkeletalMesh> CharacterMeshRef(TEXT("/Script/Engine.SkeletalMesh'/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Cardboard.SK_CharM_Cardboard'"));
if (CharacterMeshRef.Object)
{
GetMesh()->SetSkeletalMesh(CharacterMeshRef.Object);
}
// 애니메이션 지정
// 적용하고 싶은 AnimInstance의 Copy Reference 복붙 + ''삭제 및 끝에 _C 붙이기
static ConstructorHelpers::FClassFinder<UAnimInstance> AnimInstanceClassRef(TEXT("/Game/ArenaBattle/Animation/ABP_ABCharacter.ABP_ABCharacter_C"));
if (AnimInstanceClassRef.Class)
{
GetMesh()->SetAnimInstanceClass(AnimInstanceClassRef.Class);
}
- ABCharacterBase.cpp
- 설정해준 뒤, 그에 맞게 예전에 설정한 ABCharacterBase.cpp의 생성자 내용을 수정해준다.
- 컴파일 후 에디터를 실행한다.
- 캐릭터 애니메이션 시스템의 생성
- 스켈레탈 메시 컴포넌트의 애니메이션 블루프린트 클래스를 지정
- 캐릭터가 초기화될 때 AnimInstance 클래스의 인스턴스를 생성
- 캐릭터는 GetAnimInstance 함수를 사용해 애니메이션 인스턴스를 얻을 수 있음
- 애니메이션 인스턴스는 GetOwningActor 함수를 사용해 자신을 소유한 액터 정보를 얻을 수 있음
- 캐릭터 애니메이션 시스템의 설계
- 애니메이션 블루프린트는 이벤트 그래프와 애님 그래프의 두 영역으로 구성되어 있음
- 이벤트 그래프
- 이벤트로부터 상태를 파악할 수 있는 주요 변수 저장
- 애님 그래프
- 저장된 변수로부터 지정된 상태의 애니메이션을 재생
- 애님 그래프의 복잡한 상태는 State Alias로 분리해 효과적으로 설계할 수 있음
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "ABAnimInstance.generated.h"
UCLASS()
class ARENABATTLE_API UABAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
UABAnimInstance();
protected:
// AnimInstance가 처음 생성될 때 한 번 호출
virtual void NativeInitializeAnimation() override;
// 프레임마다 호출
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
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 GroundSpeed;
// 언리얼에서 bool 타입은 사이즈가 명확하지 않아서 integer형으로 선언하되, b라는 접두사를 붙여 다른 integer 형과 구분
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
uint8 bIsIdle : 1;
// 움직이고 있는지, 쉬고 있는지
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
float MovingThreshould;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
uint8 bIsFalling : 1;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
uint8 bIsJumping : 1;
// 움직이고 있는지, 쉬고 있는지
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Character)
float JumpingThreshould;
};
- UABAnimInstance .h
#include "Animation/ABAnimInstance.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
UABAnimInstance::UABAnimInstance()
{
MovingThreshould = 3.0f;
JumpingThreshould = 100.0f;
}
// AnimInstance가 처음 생성될 때 한 번 호출
void UABAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
// 오브젝트에 대한 포인트 값을 초기화
Owner = Cast<ACharacter>(GetOwningActor()); // 형변환
if (Owner) // Null 값 확인
{
Movement = Owner->GetCharacterMovement(); // Movement를 통해 캐릭터 무브먼트 객체로 부터 값을 얻어올 수 있다.
}
}
// 프레임마다 호출
void UABAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
// NativeInitializeAnimation()에서 가져온 값으로 로직 구성
if (Movement)
{
Velocity = Movement->Velocity;
GroundSpeed = Velocity.Size2D();
bIsIdle = GroundSpeed < MovingThreshould;
bIsFalling = Movement->IsFalling();
bIsJumping = bIsFalling & (Velocity.Z > JumpingThreshould);
}
}
- UABAnimInstance .cpp
- 애니메이션 블루프린트의 My Blueprint에서 기어박스 Show Inherited Variables 항목을 체크하면 상속받은 C++ 변수들을 확인할 수 있다.
- 다음 변수들을 바탕으로 애님 그래프를 구성해서 사용하면 된다.
- State Machine은 AnimGraph의 전체적인 관리를 담당한다.
- 유니티의 애니메이터와 같이 상태에 따라 전이할 수 있도록 설정해줄 수 있다.
- 이후 각 상태에 따라 애니메이션을 넣어주면 된다.
- 속도에 따라 애니메이션이 블랜딩되도록 설정하기 위해서는 한가지 애니메이션 에셋이 필요하다.
- Blend Space 1D를 사용하여 애니메이션을 블랜딩할 애니메이션 에셋을 만들어 준다.
- 메쉬는 적용할 캐릭터의 스켈레톤 메쉬를 설정하면 된다.
- 가로값에 대한 셋팅을 설정해준다.
- Idle > Walk > Run에 대한 애니메이션을 블랜딩해주기 위해서 사용할 값의 이름을 설정해주고, 해당 값의 범위 Min~Max를 설정해준다.
- 값을 설정한 후 ctrl을 누른채로 하단에서 마우스를 움직이면 아까 설정한 GroundSpeed(0~500)에 따라 애니메이션이 블랜딩 되는 것을 실시간으로 확인할 수 있다.
- 이후 애니메이션 블루프린트로 돌아가면 Asset Browser에 만든 애니메이션 에셋(BS_IdleWalkRun)이 나타나게 되고, C++로 만든 Ground Speed 변수를 연결해주면 된다.
- 애니메이션을 적용하기위해 cached pose를 만들어 준 뒤, 연결해준다.
- 연결이 되었으면, Compile을 하고 확인한다.
- Jump를 하는 행동을 생각해봤을때, Falling은 무조건 Jump 애니메이션이 나타난 다음에 나타나야할 애니메이션이기 때문에 Priority Order를 Jump 애니메이션보다 후순위인 2로 설정해준다.
- Jump에서 Falling으로 넘어갈 때 Time Remaining(ratio) 노드를 사용하여 Jump 애니메이션이 끝나기 전에 Falling애니메이션이 시작될 수 있도록 설정해준다.
- Time Remaining (ratio) (Warrior Jump) < 0.1
해당 포스트는 인프런의 <이득우의 언리얼 프로그래밍 Part2 -언리얼 게임 프레임웍의 이해>
강의를 수강하고 정리한 내용입니다.
이득우의 언리얼 프로그래밍 Part2 - 언리얼 게임 프레임웍의 이해 | 이득우 - 인프런
청강문화산업대학교에서 언리얼 엔진, 게임 수학, UEFN 게임제작을 가르치고 있습니다. - 이득우의 언리얼 C++ 프로그래밍, 넥슨 코리아 공식 교육 교재 선정 2023 - 스마일게이트 언리얼 프로그래
www.inflearn.com
'공부 > 이득우의 언리얼 프로그래밍' 카테고리의 다른 글
[Study] Part 2 - 캐릭터 공격 판정 (6/15) (0) | 2024.06.03 |
---|---|
[Study] Part 2 - 캐릭터 콤보 액션 (5/15) (2) | 2024.06.02 |
[Study] Part 2 - 캐릭터 컨트롤 설정 (3/15) (0) | 2024.05.28 |
[Study] Part 2 - 캐릭터와 입력 시스템 (2/15) (0) | 2024.05.20 |
[Study] Part 2 - 언리얼 엔진 게임 제작 기초 (1/15) (0) | 2024.05.16 |