본문 바로가기

인생언리얼TPS

3.2 알파타입버전 제작하기 - 애니메이션 FSM

	//매프레임 갱신되는 함수
	virtual void NativeUpdateAnimation(float DeltaSeconds) override;
};

1.  플레이어 적에서 사용하는 디자인에셋, 애니메이션 처리를 목표로 합니다. 상태머신, 블렌드스페이스 애니메이션몽타주

2. 지능화된 AI적

3. 카메라 셰이크 기법

 

3.2-1 플레이어 알파타입 버전 업그레이드하기

마켓플레이스에서 애니메이션 스타터팩을 다운받아 현재 프로젝트에 적용해줍니다.

다운 받아보니 Mesh는 SK_Mannequin이고 Skeleton은 UE4_Mannequin_Skeleton가 들어 있네요

SK_Mannequin 메시위를 우클릭해 레퍼런스를 카피해 TPSPlayer생성자에 메시를 불러온다.

// Sets default values
ATPSPlayer::ATPSPlayer()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	// 1. 스켈레탈메시 데이터를 불러오고 싶다.
	ConstructorHelpers::FObjectFinder<USkeletalMesh> tempMesh(TEXT("/Game/AnimStarterPack/UE4_Mannequin/Mesh/SK_Mannequin.SK_Mannequin"));
	if (tempMesh.Succeeded()) {
		GetMesh()->SetSkeletalMesh(tempMesh.Object);
		// 2. Mesh 컴포넌트의 위치와 회전 값을 설정하고 싶다.
		GetMesh()->SetRelativeLocationAndRotation(FVector(0, 0, -90), FRotator(0, -90, 0));
	}

 

StaticMesh는 변경이 불가능하지만 SkeletonMesh는 메시 데이터와 뼈대 데이터로 나누어져 있어 애니메이션에 적용할수 있습니다. 뼈대를 회전시킬수 있어 애니메이션이 가능합니다.

3종류의 파일이 있는데 Skeletal Mesh, PhysicsAsset, Skeleton이 있습니다.

 

 

아무 파일이나 누르면 에디터가 열립니다. 현재는 뼈다구 skeleton모드네요

Character Bones All Hierachy를 선택하면 뼈대를 확인할 수 있습니다.

오른쪽 아래 Asset Browser의 애니메이션을 선택하면 뷰포트에서 동작을 확인할 수 있습니다.

BP_TPSPlayer 블루프린트를 열고 Components Mesh를 선택하고 Detail에서 Animation Class를 ABP_AnimationAsset으로 변경합니다.

그럼 애니메이션 개별 파일을 선택할 수 있습니다. Idel_Rifle_IronSights를 선택합니다. 동작을 뷰포트에서 확인가능합니다.

하지만 게임중 플레이어의 애니메이션을 상황에 맞게 바꿔져야 하므로 이걸 블루프린트로 제어해야 합니다.  Animation Mode를 다시 Use Animation Blueprint로 바꾸면 ABP_Manny_C가 있지만 우리의 블루프린트를 만들어 보겠습니다.

블루프린트 폴더안에 우클릭하고 Animation Blueprint를 선택합니다.

AnimStaterPack에 있던 UE4_Mannequin_Skeleton을 선택합니다. 이름을 ABP_Player로 합니다.

에디터가 열립니다.

Asset Browser에서 idle로 필터후 Idel_Rifle_IronSights를 끌어다 AnimGraph창에 놓고 OutputPose와 연결해줍니다.

 

컴파일 저장하면 프리뷰에서 확인할 수 있습니다.

이제 BP_TPSPlayer 블루프린트의 메시를 선택후 Anim Class를 ABP_Player로 선택하면 뷰포트에서 미리볼수 있습니다.

 

하지만 아직도 하나의 동작만 연결되어있어 애니메이션 상태머신을 만들어 상태에 따라 적절한 애니메이션이 플레이 되도록해보겠습니다.  블루프린트만으로도 가능하지만 C++클래스를 만들어 연동시켜보겠습니다.

 

PlayerAnim.h를 열어 speed 변수를 추가합니다.

class TPSPROJECT_API UPlayerAnim : public UAnimInstance
{
	GENERATED_BODY()
public:
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category=PlayerAnim)
	float speed = 0;
};

이 speed변수는 좀전에 만든 ABP_Player에서 사용합니다. 열어보면 AnimInstance가 부모인데 우리가 만든 클래스로 갈아줘야 합니다. ToolBar의 ClassSettings를 눌러 디테일에서 PlayerAnim을 선택해줍니

My Blueprint 톱니바퀴를 눌러 Showw Inherited Variables를 선택하면 Variables에 방금만든 Speed를 확인할수 있습니

 Idel_Rifle_IronSights 을 지워주고 AnimGraph위에 우클릭후 StateMachien을 추가하고 연결해주고 이름을 MoveFSM으로 바꾸고 클릭해서 들어갑니다.

입장하면 Entry 노드외에 아무것도 없지만 오른쪽 아래 AssetBwoser에서 애니메이션을 끌어다 다음과 같이 연결합니다.

애니메이션 사이 동그라미가 조건인데 다음과 같이 넣어줍니다.

Idle to Walk / Walk to Idle

컴파일후 speed변수의 값을 디테일의 창에서 0.2로 설정하면 플레이어가 걷습니다.

이제 블루프린트에서 상황에 맞게 자동으로 speed변수값을 변경되게 해보겠습니다. EventGraph 모드를 선택합니다.

이미 두개의 노드가 있는데 Try Get Pawn Owner로 Cast후 Character의 스피드를 체크할수 있습니다.

Cast된 BP_TPSPlayer에서 velecity를 얻어 스칼라값으로 바꿔주면 speed가 됩니다.

플레이 해보면 앞뒤좌우로 움직일때 걷기 시작합니다. 우리는 앞으로 움직일때만 걷게 하고 싶습니다. 그럴려면 앞방향과 내적해주면 됩니다.

MoveFSM State에 Walk_Bwd_Rifle_IronSights를 추가하고 조건을 넣어줍니다. 뒤로가니까 속도가 마이너스입니다.

여태까지 한걸 C++에서 구현해보겠습니다.

PlayerAnim.h로 이동합니다.

블루프린트의 Event Blueprint Update Animation노드가 NativeUpdateAnimation()함수 입니다 이걸 추가해줍니다.

	//매프레임 갱신되는 함수
	virtual void NativeUpdateAnimation(float DeltaSeconds) override;
};

PlayerAnim.h에 구현해 줍니다. 

#include "PlayerAnim.h"
#include "TPSplayer.h"

void UPlayerAnim::NativeUpdateAnimation(float DeltaSeconds)
{
	auto ownerPawn = TryGetPawnOwner();
	auto player = Cast<ATPSPlayer>(ownerPawn);

	if (player) {
		FVector velocity = player->GetVelocity();
		FVector forwardVector = player->GetActorForwardVector();
		speed = FVector::DotProduct(forwardVector, velocity);
	}
}

이제 점프를 만들어 보겠습니다 애니메이션 팩은 점프가 한동작으로 이루어져.  3동작의 점프 애니메이션이 교재 자료에 있습니다. import

PlayerJump.zip
0.17MB

 

Skeleton을 UE4_Mannequin_Skeleton로 설정하고 Import해보면 애니메이션 길이가 짧다는 에러가 납니다. 전 Snap to Closest Frame Boundary를 체크해 해결했습니다.

 

PlayerAnim.h 에 isInAir 변수를 추가해줍니다.

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = PlayerAnim)
	bool isInAir = false;

PlayerAnim.cpp 에 isInAir를 설정해 줍니다.

#include <GameFramework/CharacterMovementComponent.h>

void UPlayerAnim::NativeUpdateAnimation(float DeltaSeconds)
{
//생략
	if (player) {
//생략
		auto movement = player->GetCharacterMovement();
		isInAir = movement->IsFalling();
	}
}

AnimGraph에 JumpStart, Loop, End를 3가지를 끌어다 놓고 다음과 같이 연결하고

4가지 조건을 설정합니다. 

Idle -> JumpStart

JumpStart->JumpIdle

JumpIdle->JumpEnd

JumpEnd->Idle