Animation을 character에 적용시키기 위해서 Animation Blueprint를 이용해야 한다.
Content Browser에서 우클릭 후 Animation Blueprint를 하나 생성한다.
우측 하단의 Asset Browser에서 가만히 서있는 애니메션을 끌어다 Output Pose와 연결시킨다.
Character Blueprint에서 우측의 Details 패널에 있는 Animation에 방금 만들 ABP파일을 Anim Class에 넣어주고 실행하면 애니메이션이 재생되는 캐릭터를 볼 수 있다.
"이동중인가?"를 bool 타입의 변수로 저장시키고, 값에 따라 이동하는 애니메이션을 재생하거나 가만히 서있는 애니메이션을 재생하거나 할 수 있다.
Blueprint에서 구현
- 초기화
우선 Character를 추가해준다.
속도, 공중부양 유무 등과 같은 변수는 Animation Blueprint가 아닌 Character에 속한 변수이다. 이를 참조하기 위해서는 Character변수가 필요하다.
- Object Reference
특정한 인스턴스를 가리키는 변수이다. 즉 이미 생성된 객체를 가리키는 변수이며 객체의 속성, 함수등에 직접적으로 접근 가능하게 한다.- Class Reference
클래스 자체를 가리키는 변수이다. 클래스의 유형을 확인하는 용도로 사용되며, 동적으로 객체를 생성(여러 유형의 적)할 때 사용한다.- 나머지는 객체 또는 클래스 자체에 대한 참조를 보유.
생성한 Character는 아무것도 없으므로 초기화시켜야 한다.
- Event Blueprint Initialize Animation
Bluepirnt class 내에서 애니메이션 초기화시 발생. 일반적으로 애니메이션을 초기화하거나 관련 변수를 설정하는 등의 초기화 작업을 수행하는데 사용.- Try Get Pawn Owner
해당 노드는 Pawn Object를 참조 가능하게 하고 Pawn Object Reference를 반환한다. 하지만 Character의 경우 Character Object Reference이므로 Casting을 해주어야 한다.- Cast To BP_CLASS_NAME
Pawn을 Character로 형변환(casting)하기 위해 사용한다.
필요한 것은 CharacterMovement에 대한 것들이므로 Setter에서 Get Character Movement로 연결시킨다.
직접 변수를 생성해 노드를 연결시켜도 되지만, CharacterMovement에서 Promote to variable를 클릭해 연결하는 방법도 있다.
이제 CharacterMovement라는 변수를 통해 움직임 관련된 값들을 불러올 수 있다.
필요에 따라 이름을 변경하여 사용하는 것도 가능하다.
캐릭터가 움직이면 매 프레임마다 관련된 값들이 변경될 것이므로, 데이터를 얻기 위해서 Event Blueprint Update Animation노드를 사용해야 한다.
우선 MovementComponent의 GetVelocity를 통해 캐릭터의 속도를 얻을 수 있다.
이를 VectorLengthXY를 통해 벡터의 크기만 따로 값을 빼낸다(Z에 대한 값은 필요없으므로 VectorLengthXY 사용).
위와 똑같이 Promote to variable를 통해 바로 변수를 생성하고 EventUpdateAnimation노드와 연결한 후 변수명을 GroundSpeed로 변경한다.
- State Machine 에서 초기화한 변수를 이용한 애니메이션 활용
AnimGraph에서 우클릭후 StateMachine을 검색하여 노드를 추가한다.
생성한 StateMachine을 더블클릭하여 Idle과 Run State를 추가한다.각 State에 맞는 애니메이션을 OutputAnimationPose 노드와 연결한다.
그리고 StateMachine으로 나와 Transition Rule를 설정해준다.
Idle->Run 상태일 때의 조건은 GroundSpeed가 0이 아닌 경우이므로 위와 같이 조건을 걸어준다.
Run->Idle 상태일 때의 조건은 GroundSpeed가 0인 경우이므로 위와 같이 조건을 걸어준다.
이제 캐릭터가 움직일 때는 달리는 애니메이션이, 캐릭터가 움직이지 않을 때는 가만히 서있는 애니메이션이 재생된다.
마지막으로 캐릭터가 걷는 애니메이션은 무한정 재생되는 것이 아니다.
그러므로 LoopAnimation을 활성화하여 계속 걸어가도 애니메이션의 재생이 멈추지 않도록 한다.cpp에서 구현
cpp에서 구현하기 위해서는 AnimInstance class가 필요하다.
1. Event노드 구현
AnimInstance Class를 생성한 후 먼저 해줘야할 것이 몇가지 있는데, Blueprint에서 사용했던 노드인 EventBlueprintInitializeAnimation 과 EventBlueprintUpdateAnimation을 구현하는 것이다.
우선 헤더파일에 선언먼저 해준다.// Solution명 = Study, AnimInstance명 = WraithAnimInstance UCLASS() class STUDY_API UWraithAnimInstance : public UAnimInstance { GENERATED_BODY(); public: // Blueprint에서 EventBlueprintInitializeAnimation 노드 virtual void NativeInitializeAnimation() override; // Blueprint에서 EventBlueprintUpdateAnimation 노드 virtual void NativeUpdateAnimation(float DeltaTime) override; }
이어서 cpp파일에 구현한다.
... // AnimInstance명 WraithAnimInstance // Blueprint에서 EventBlueprintInitializeAnimation 노드 void UWraithAnimInstnace::NativeInitializeAnimation() { Super::NativeInitializeAnimaion(); } // Blueprint에서 EventBlueprintUpdateAnimation 노드 void UWraithAnimInstance::NativeUpdateAnimation(float Delta) { Super::NativeUpdateAnimation(DeltaTime); } ...
- 필요한 변수 선언
Character, MovementComponent, GroundSpeed와 같은 필요한 변수들을 선언하고 구현한다.
우선 헤더파일에 선언을 진행한다.... class AWraithCharacter; class CharacterMovementComponent; ... private: // Character에 있는 값(속도, 공중부양 여부 등)을 이용하기 위한 변수 UPROPERTY(BlueprintReadOnly, Category = "Movement", meta = (AllowPrivateAccess = "true)) AWraithCharacter* WraithCharacter; // Character의 MovementComponent를 사용하기 위한 변수 UPROPERTY(BlueprintReadOnly, Category = "Movement", meta = (AllowPrivateAccess = "true")) UCharacterMovementComponent* WraithCharacterMovement; // Character Speed UPROPERTY(BlueprintReadOnly, Category = "Movement", meta = (AllowPrivateAccess = "true")) float GroundSpeed;
이어서 cpp파일에 구현한다.
... #include "Characters/WraithCharacter.h" #include "GameFramework/CharacterMovementComponent.h" #include "Kismet/KismetMathLibrary.h" ... // Blueprint에서 EventBlueprintInitializeAnimation 노드 void UWraithAnimInstnace::NativeInitializeAnimation() { Super::NativeInitializeAnimaion(); // Pawn을 Character로 캐스팅 WraithCharacter = Cast<AWraithCharacter>(TryGetPawnOwner()); // nullptr 검사 if(WraithCharacter) { // WraithChracterMovement에 CharacterMovement 할당 // GameFramework/CharacterMovementComponent.h 필요 WraithChracterMovement = WraithCharacter->GetChracterMovement(); } } // Blueprint에서 EventBlueprintUpdateAnimation 노드 void UWraithAnimInstance::NativeUpdateAnimation(float Delta) { Super::NativeUpdateAnimation(DeltaTime); // nullptr 검사 if(WraithCharacterMovement) { // Kismet/KismetMathLibrary.h 필요 GroundSpeed = UKismetMathLibrary::VSizeXY(WraithChracterMovement->Velocity) } }
마지막으로 애니메이션 블루프린트 클래스의 상단에 있는 Class Settings를 누르고 우측의 Parent class에 방금 만든 AnimInstanceClass를 넣어주면 된다.
점프 구현
- 점프 관련 노드와 코드 추가
https://velog.io/@groot616/Pawn-Class-mqg22cdk
BindAxis와 거의 동일
먼저 Project Settings 에서 Jump Action Mapping을 생성한다.
Blueprint에서 구현
Character class는 기본적으로 Jump함수를 지원해주므로 노드를 생성해 연결해주면 끝.cpp에서 구현
// character명 = WraithCharacter void AWraithCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { ... // BindAction // BindAction(FName ActionName, EInputEvent KeyEvent, AWraithCharacter* Object, void (AWraithChrarcter::*Func)()) PlayerInputComponent->BindAction(FName("Jump"), IE_Pressed, this, &ACharacter::Jump); ... }
- EInputEvent KeyEvent
ActionMapping이므로 키를 누르거나 키를 때거나에 따라 바인딩가능해야 함.
(총을 격발하려고 마우스를 클릭하고, 마우스클릭을 멈췄을 경우 격발되지 않도록 함)
- 점프 관련 애니메이션 추가
점프는 단순히 "점프한다" 하나의 애니메이션이 아닌 기본적으로 점프준비자세->점프->고점찍고낙하->착지 단계를 거치게 된다.
앞의 두단계는 스페이스바를 누르면 재생되도록 되어있으니 추가적인 조건이 필요없지만, 고점찍고 낙하와 착지단계는 "낙하중인지에 대한 여부"가 필요하다.
먼저 헤더파일에 bool타입 변수를 선언한다.... private: // 낙하 여부 UPROPERTY(BlueprintReadOnly, Category = "Movement", meta = (AllowPrivateAccess = "true")) bool IsFalling; ...
이어서 cpp파일에 코드를 작성한다.
// AnimInstance명 = WraithAnimInstance void UWraithAnimInstance::NativeUpdateAnimation(float Delta) { ... if(WraithCharacterMovemenmt) { ... IsFalling = WraithCharacterMovement->IsFalling(); ... } ... }
이제 ABP_WraithCharacter에서 IsFalling값을 사용할 수 있다.
ABP파일에 Main States라는 새로운 StateMachine을 추가하고 Output Pose노드와 연결시켜준다.
Main States는 기본적인 상태(Idle, Jump, Falling, Running등)를 나타내는 StateMachine으로 사용할 예정이다.
Main States에 점프를 구현하기 위한 state를 추가해준다.
- OnGround
이전에 사용했던 Ground Locomotion을 그대로 이용한다.
StateMachine을 Cached Pose를 이용하면 다른 곳에서도 사용할 수 있게 된다.
OnGround State에서 저장해둔 포즈를 사용한다.- InAir
InAir State에서도 적절한 애니메이션을 찾아 output node와 연결시켜준다.
이때 애니메이션이 반복재생되지 않도록 필요에 따라 Loop를 비활성화시켜주어야 한다.
(몇몇 애니메이션의 경우 점프하기 위한 도움닫기 애니메이션이 같이 있을 수 있음)
OnGround->InAir로 가는 Transition Rule도 정해주어야 한다. 점프상태=떨어지는 상태이므로 위에서 추가해 둔 IsFalling을 이용해 조건을 달아준다.- Land
Land State에서도 적절한 애니메이션을 찾아 Output Node와 연결시켜준다.
착지에 대한 Transition Rule은 당연히 IsFalling에 Not을 취한 것과 같다.
Land state가 끝나면 자동으로 OnGround state가 재생되도록Automatic Rule Based on Sequence Player in State
를 활성화 시켜준다.
이대로 컴파일후 실행하면 Land state 애니메이션을 전부 재생해야 다시 OnGround State의 애니메이션을 재생하는 문제가 발생한다. Land관련 애니메이션이 길 경우 생기는 문제이므로 이를 해결해 주어야 한다.
Land->OnGround의 새로운 Transition Rule을 하나 만들어 준다.
Land에서 Ground로 가기 위한 추가 조건은 다음과 같다.
Land 애니메이션의 재생이 0.15sec 이상 재생되었을 경우, 그리고 GroundSpeed가 0이상일 경우(0인 상태에서 점프를 다시 시도할 경우, 이동중인 상태에서 ground locomotion으로 진입할 경우)이다.
Weapon class 이후 정리
인게임에서 필요한 애니메이션은 한둘이 아니므로 이것저것 추가하다보면 어지러운 상태가 될것이므로 깔끔하게 정리할 필요가 있다.
MainStates를 따로 만들면 관리하기 편하다.
ABP_MainStates라는 애니메이션 블루프린트를 하나 만든다.
기존에 있던 애니메이션 블루프린트에서 Ground Locomotion과 Main States를 복사해서 방금 생성한 ABP_MainStates에 붙여넣기한다.
컴파일을 시도하면 없는 변수들에 대한 에러가 발생한다.
오류가 발생한 노드들을 우클릭하고Create variable 'NODE_NAME'
을 클릭하면 해당 변수가 자동으로 생성된다.
모든 변수들을 생성하고 Main States를 Output Pose와 연결시켜준다.
다시 기존의 캐릭터 애니메이션 블루프린트로 돌아와서,Linked Anim Graph
노드를 추가하고 우측의 Details 패널에서Instance Class
에 방금 생성한 ABP_MainStates를 추가해준다.
ABP_WraithCharacter의 변수들과 ABP_MainStates의 변수들은 다른 파일의 변수들이므로 맞게 바인딩해야 한다. 우측 Details 패널의Exposable Properties
에서Expose As Pin
을 클릭하면 ABP_WraithChracter의 변수들에 바인딩할 수 있다.
마지막으로 Main States Cached pose에 연결해주면 깔끔하게 정리된다.
다른 방법도 있다.
Control Rig를 정리하기 위해 다른 방법을 쓴다.
먼저 ABP_Wraith_IK 애니메이션 블루프린트를 생성한다.
ABP_WraithCharacter에서 우클릭후Linked Anim Graph
를 검색하고 위쪽에ABP_Wraith_IK - Linked Anim Graph
노드를 생성한다.
ABP_Wraith_IK파일에서 우클릭 후Input Pose
노드를 생성한다.
우측 Details 패널에서 노드명을 MainStates로 변경시켜준다.
다시 ABP_WraithCharacter로 돌아와 방금 생성한 노드를 우클릭하고Refresh Nodes
를 클릭하면 함수처럼 사용 가능하게 된다.
ABP_Wraith_IK로 돌아와서 MainStates를 제외한 나머지 변수들을 자동생성해주고
방금 생성한 Input Nodes를 cached pose하고 연결한다.
ABP_WraithCharacter로 돌아가서 MainStates를 연결시켜주고
ABP_Wraith_IK의 변수들을 바인딩시켜주면 깔끔하게 정리 가능하다(우측 디테일 패널에 바인딩할 변수가 보이지 않을 경우,Refresh Nodes
이후 ABP_Wraith_IK에서 변수선언 한것이므로 한번더 Refresh Nodes하면 생김).
핀 말고 직접 넣는것도 가능하다.
애니메이션에서 스켈레톤 변경
변경할 스켈레톤 선택 후 상단의 +Key를 누르면 변경 가능(12.119).