블루프린트 사용하는 이유
유지보수가 쉬움
Animation Blueprint
C++ 클래스 생성에서 All Classes를 클릭하고 AnimInstance를 하나 만든다.
블루프린트에서 Animation Blueprint 생성을 누른다.
Skeleton을 본인이 사용할 것을 골라주고, Parent Class를 생성한 AnimInstance의 이름을 골라 생성해준다.
제대로 생성되었다면, Class Settings - Class Options - Parent Class에 해당 AnimInstance가 들어간 것을 확인할 수 있다.
//메쉬의 애니메이션 설정에 애니메이션 인스턴스 삽입
static ConstructorHelpers::FClassFinder<UAnimInstance> AnimInstance(TEXT("/Game/Blueprints/ABP_Player.ABP_Player_C"));
if (AnimInstance.Class)
{
GetMesh()->SetAnimInstanceClass(AnimInstance.Class);
}
경로를 지정해줄때, Class를 가져올 것이므로 경로 끝에_C를 추가해주자.
아래의 경우에도 동작은 한다.
PlayerAnimInstance.h
PlayerAnimInstance.cpp
NativeInitiallizeAnimation
Owner에 GetOwningActor를 하여 가져올 때 Cast를 통해서 캐릭터형으로 받고 있다.
찾은 Owner에 CharacterMovement를 Owner->GetCharcterMovement()를 통해 Movement에 넣고 있다.
Super::NativeInitializeAnimation();
//Cast ACharacter
Owner = Cast<ACharacter>(GetOwningActor());
//Movement
if (Owner)
{
Movement = Owner->GetCharacterMovement();
}
NativeUpdateAnimation
앞서 찾아온 Movement와 Owner를 이용해서, Velocity, MoveSpeed, isFalling, Angle의 값을 할당해주고 있다.
Super::NativeUpdateAnimation(DeltaSeconds);
//Movement를 가져와서 값 할당
if (Movement)
{
Velocity = Movement->Velocity;
MoveSpeed = Velocity.Size2D();
isFalling = Movement->IsFalling();
Angle = UAnimInstance::CalculateDirection(Velocity, Owner->GetActorRotation());
}
AnimationBlueprint - My Blueprint의 톱니바퀴 버튼을 눌러, Show Inherited Variables 를 눌러준다.
플레이어의 MoveSpeed를 BlendSpace의 이동 애니메이션에 사용할 것이라서 연결해준다.
UAnimInstance::CalculateDirection
캐릭터에 무기를 추가하기 위해서, 캐릭터의 스켈레톤 메쉬를 클릭하여 열고, Add Socket을 통해 Weapon Socket을 추가한다.
다음으로 Add Preview Asset을 통해서, 추가할 Weapon의 위치를 조정해준다.
하지만, 이러한 방식을 사용하면, 상위의 Bone이나 그러한 것들 때문에, Weapon_Socket_R이 영향을 받아서 제대로 된 애니메이션이 나오지 않을 것이다.
무기를 더해줄 때는, 어느 부분까지 영향을 미칠 수 있는 가를 생각해서, Socket을 만들어 넣어야한다.
제대로 된 애니메이션을 위해서 hand_r의 밑에 Socket을 만들고 Preview를 통해서 적절한 각도, 위치로 설정한다.
Weapon에 스태틱메쉬를 만들어 WeaponMesh로 이름을 정한다.
SetupAttachment를 통해, 플레이어의 메쉬에 Weapon을 하위로 붙입니다.
ConstructorHelpers::FObjectFinder를 통해, Weapon의 스태틱 메쉬의 위치를 찾습니다.
Succeeded()를 통해 오류를 방지하고, 제대로 가져왔는지 확인합니다.
제대로 가져왔다면, SetStaticMesh로 SM_Weapon에 넣어줍니다.
AttachToComponent를 통해, 플레이어 캐릭터 메쉬의 hand_rSocket에 상대좌표로 붙입니다.
AttachToComponent(붙일 Mesh 이름, 붙일 방식, TEXT("붙일 본/소켓의 이름"));
//무기 추가
SM_Weapon = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponMesh"));
SM_Weapon->SetupAttachment(GetMesh());
static ConstructorHelpers::FObjectFinder<UStaticMesh> WeaponMesh(TEXT("/Script/Engine.StaticMesh'/Game/Asset/Weapons/FPS_Weapon_Bundle/Weapons/Meshes/AR4/SM_AR4.SM_AR4'"));
//SM_Weapon에 Ar4 추가
if (WeaponMesh.Succeeded())
{
SM_Weapon->SetStaticMesh(WeaponMesh.Object);
}
// hand_rSocket에 SM_Weapon을 추가한다.
SM_Weapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("hand_rSocket"));
버튼을 누르는 동안 조준과 조준을 푸는 것을 위해서 다음과 같이 만든다.
ETriggerEvent::Triggered : 매 틱마다
ETriggerEvent::Started : 맨 처음 한 번
ETriggerEvent::Completed : 맨 마지막에 한 번
AnimInstance를 사용하므로, cpp의 상위에 선언해주자.
C++ 상에서 사용하기 위해서 정의해준다.
여기서 BlueprintReadWrite를 통해, 우리가 원하는 Montage를 할당할 수 있게 된다.
대신에, 이러한 방식의 경우 Montage가 없을 경우,
문제가 발생하므로, 코드 작성시에 Montage가 존재 하는가에 대한 확인이 필요하다.
따라서 코드 작성시에
if (RifleAimMontage)
{
AnimInstance->MontagePlay(RifleAimMontage);
}
애니메이션 블루 프린트의 Locomotion에 Slot을 하나 만들어서 연결한다.
해당 몽타주는 우리가 만든 Default 슬롯을 통해서 플레이 된다.
몽타주를 재생할 슬롯은 몽타주에서 설정 가능하다.
Montage를 할당한 후에 AnimInstance->Montage_Play(몽타주); 를 통해 플레이 하면, 애니메이션이 재생되기는 하지만, 중간에 끊기거나 제대로 플레이 되지 않을 것이다.
왜냐하면, Montage_Play에 기본 설정시에 1.0f시간 만큼만 재생되기 때문이다.
AnimInstance->Montage_Play(재생할 몽타주 , End Time);
이번의 경우는 0.3f로 설정해주었다.
잘못된 애니메이션 시퀀스의 경우는 약간의 노력으로 수정될 수도 있다.
Additive Settings의 Additive Anim Type
Base Pose Animation의 애니메이션 시퀀스 선택
Root Motion Force Root Lock 여부 변경
등을 통해서 잘못되는 경우를 막을 수 있다.
참고🐋🐋🐋🐋🐋
ConstructorHelpers
https://dev.epicgames.com/documentation/ko-kr/unreal-engine/gameplay-classes-in-unreal-engine?application_version=5.5#%EC%83%9D%EC%84%B1%EC%9E%90%EC%8A%A4%ED%83%9C%ED%8B%B1%EB%B0%8F%ED%97%AC%ED%8D%BC
NativeInitializeAnimation
https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/Animation/UAnimInstance/NativeInitializeAnimation?application_version=5.5
NativeUpdateAnimation
https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/Animation/UAnimInstance/NativeUpdateAnimation?application_version=5.5
GetAnimInstance
https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/Components/USkeletalMeshComponent/GetAnimInstance
AttachToComponent
https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/GameFramework/AActor/AttachToComponent?application_version=4.27
ETrigger
https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Plugins/EnhancedInput/ETriggerEvent?application_version=5.5
Montage_play
https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/Animation/UAnimInstance/Montage_Play