그냥 게임개발자

[UE5] - 4장 캐릭터 생성, 애니메이션 기초(C++, 블루프린트) 본문

UE5_Tutorial1

[UE5] - 4장 캐릭터 생성, 애니메이션 기초(C++, 블루프린트)

sudoju 2023. 9. 25. 15:03

본 강의는 인프런 루키스 강의를 보고 작성한 글인점을 알려드립니다.

1. 캐릭터 생성

2. GameModeBase C++로 만들기

3. 애니메이션

 

 

1. 캐릭터 생성

우리는 저번에 1인칭 플레이어 캐릭터를 생성해보았다.

모르시는 분들은 -> https://sudoju.tistory.com/54

 

이번에는 3인칭 플레이어 캐릭터를 생성해보려고 한다.

 

우리는 캐릭터 모델이 따로 없기에 마켓플레이스에서 에픽게임즈가 무료로 제공하는 파라곤 캐릭터를 이용할 것이다.

 

 

아주 좋은 캐릭터들이 많다 마음에 드는 것을 다운받아 프로젝트에 추가하자.

 

이제 우리는 저번에 만들었던 PlayerCharacter클래스를 버리고 TutorialCharacter라는 클래스를 만들어서 관리할 것이다.

만약 또 오류가 난다면 cpp파일에 .h파일 포함하는 것의 주소를 잘 확인해보자.

폴더를 따로 만들어서 관리를 안한다면 TutorialCharacter.h만 있는 것이맞고

필자처럼 FirstProject폴더에 Player폴더에 관리한다고 하면 저렇게 써주는 것이 맞다.

 

일단 이 TutorialCharacter클래스를 블루프린트로 만들어보자.

여기서 알아야 할 것은

C++클래스 -> 블루프린트 O

블루프린트 -> C++ 클래스 X

라는 것을 알아야 한다.

 

BP_MyTutorialCharacter

이렇게 만든 것을 확인하고 블루프린트를 확인해보자.

일단 C++ 클래스를 작성하기 전에 일단 우리가 해야 할 것을 미리 프로토타입을 만들보자.(추가한 컴포넌트들과 메쉬는 다시 원래대로 돌려놔야 하니 다시 삭제하기 귀찮은 분들은 그냥 이렇게 설정하는 거구나 하고 보자)

1. SpringArm 추가

2. Camera 추가

3. 캐릭터 메쉬 추가

 

SpringArm

Camera

 

Mesh

이렇게 설정해주자

Location 0.0, 0.0, -88.0

Rotation 0.0, 0.0, -90.0

 

이 것을 토대로 C++ 클래스로 작성해보자.

 

TutorialCharacter.h

protected:
	UPROPERTY(VisibleAnywhere)
	class USpringArmComponent* SpringArm;

	UPROPERTY(VisibleAnywhere)
	class UCameraComponent* Camera;

카메라와 스프링 암을 전방선언으로 추가해주자.

 

TutorialCharacter.cpp

ATutorialCharacter::ATutorialCharacter()
{
 	// 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;

	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SPRINGARM"));
	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("CAMERA"));

	SpringArm->SetupAttachment(GetCapsuleComponent());
	Camera->SetupAttachment(SpringArm);

	SpringArm->TargetArmLength = 200.f;
	SpringArm->SetRelativeLocationAndRotation(
		FVector(0.f, 50.f, 70.f),
		FRotator(0.f, 0.f, 0.f)
	);
	SpringArm->bUsePawnControlRotation = true;

	GetMesh()->SetRelativeLocationAndRotation(
		FVector(0.f, 0.f, -88.f),
		FRotator(0.f, -90.f, 0.f)
	);

	static ConstructorHelpers::FObjectFinder<USkeletalMesh> SM(TEXT("스켈레탈 메쉬주소"));
    
    if (SM.Succeeded())
	{
		GetMesh()->SetSkeletalMesh(SM.Object);
	}
}

빌드 해보고 확인해보자.

잘 생성이 된것을 볼 수가 있다.

 

여기서 SpringArm은 그냥 셀카봉이라고 보면된다.

그 위치에 카메라를 달아준다라고 생각하면 편하다.

 

이제 메쉬도 잘 설정했고 카메라도 잘 설정했으니

 

움직이는 코드를 써보자.

 

TutorialCharacter.h

public:
	void MoveForward(float Value);
	void MoveRight(float Value);
	void Turn(float Value);
	void LookUp(float Value);

 

TutorialCharacter.cpp

void ATutorialCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &ATutorialCharacter::Jump);

	PlayerInputComponent->BindAxis(TEXT("MoveForward"), this, &ATutorialCharacter::MoveForward);
	PlayerInputComponent->BindAxis(TEXT("MoveRight"), this, &ATutorialCharacter::MoveRight);
	PlayerInputComponent->BindAxis(TEXT("TurnCamera"), this, &ATutorialCharacter::Turn);
	PlayerInputComponent->BindAxis(TEXT("LookUp"), this, &ATutorialCharacter::LookUp);
}

void ATutorialCharacter::MoveForward(float Value)
{
	AddMovementInput(GetActorForwardVector(), Value);
}

void ATutorialCharacter::MoveRight(float Value)
{
	AddMovementInput(GetActorRightVector(), Value);
}

void ATutorialCharacter::Turn(float Value)
{
	AddControllerYawInput(Value);
}

void ATutorialCharacter::LookUp(float Value)
{
	AddControllerPitchInput(Value);
}

 

우리는 저번 글에서 프로젝트 세팅에 Input매핑을 다 해놓았기 때문에 건너뛰겠다.

그럼 빌드하자.

 

2.GameModeBase C++

GameModeBase를 Cpp로 생성할 것이다.

이제 우리는 우리가 C++클래스로 만든 TutorialCharacter를 BP로 만들었으니 GameModeBase의 DefaultPawnClass를 BP_TutorialCharacter로 가져오는 코드를 작성하자.

 

	static ConstructorHelpers::FClassFinder<ACharacter> BP_Char(TEXT("BP_TutorialCharacter주소_C"));

	if (BP_Char.Succeeded())
	{
		DefaultPawnClass = BP_Char.Class;
	}

뒤에 꼭'_C'를 붙여야 한다.

언리얼 규칙이라고 한다.

이제 빌드를 해보고 월드세팅을 확인해보자

잘 변경이 된 것을 확인하고 플레이해보자.

 

잘 확인되었다.

 

3. 애니메이션

우리는 애니메이션을 하나의 클래스로 관리하기 위해 AnimInstance라는 클래스를 새로 생성하자.

생성하고 이를 통해 애니메이션 블루프린트를 생성하자.

파라곤에서 다운받은 스켈레톤을 선택하고 클래스는 우리가 만든 TutorialAnimInstance로 선택하자.

이제 이 블루프린트를 더블클릭하면 아래와 같이 창이 나오는데 State Machine을 추가하자.

StateMachine을 더블클릭해서 이 안에서 애니메이션을 관리할 것이다.

포인터를 드래그해서 놓으면 창이 나오는데 AddState를 클릭해주자.

이런식으로 스테이트를 만들어주자.

이제  Ground를 더블클릭해서 애니메이션을 추가해주자.

이런 빈창에서 블렌드스페이스를 만들어 줄 것인데 우리는 블렌드 스페이스를 만든 적이 없다.

블렌드 스페이스를 만들러 가자.

더블 클릭하면 이런 창이 나온다.

우리가 원하는 애니메이션들은 직진, 후진, 좌, 우, Idle 상태이다.

일단 왼쪽에 Asset Details에서 사전 설정을 해보자.

이렇게 설정을 마친뒤 애니메이션을 추가하자.

각 파라곤 마다 애니메이션 이름이 다를 수 있다.

대부분 똑같으니 잘 배치해주자.

Jog_Fwd -> Horizontal 0.0, Vertical 1.0

Jog_Bwd -> Horizontal 0.0, Vertical -1.0

Jog_Left -> Horizontal -1.0, Vertical 0.0

Jog_Right -> Horizontal 1.0, Vertical 0.0

Idle_Combat -> Horizontal 0.0, Vertical 0.0

 

그럼 이상태에서 Ctrl을 누른 상태에서 애니메이션을 직접 확인할 수 있다.

 

이제 블렌드 스페이스 작업은 완료했으니 다시 애니메이션 블루프린트로 돌아가서 넣어보자.

하단 오른쪽에 AssetBrowser에 살펴보면 우리가 만든 BS_TutorialMove가 있다.

드래그 앤 드롭 해도 되고

직접 검색해도 된다.

이제 우리는 추가가 완료가 되었는데 Horizontal하고 Vertical에 값을 넣어주는 역할을 해주는 변수가 없다...

그렇다면 AnimInstance클래스에서 만들어보자.

TutorialCharacter.h

public:
	UPROPERTY()
	float MoveForwardValue = 0;
	UPROPERTY()
	float MoveRightValue = 0;

TutorialCharacter.cpp

void ATutorialCharacter::MoveForward(float Value)
{
	MoveForwardValue = Value;
	AddMovementInput(GetActorForwardVector(), Value);
}

void ATutorialCharacter::MoveRight(float Value)
{
	MoveRightValue = Value;
	AddMovementInput(GetActorRightVector(), Value);
}

AnimInstance.h

UCLASS()
class FIRSTPROJECT_API UTutorialAnimInstance : public UAnimInstance
{
	GENERATED_BODY()
	
	virtual void NativeUpdateAnimation(float DeltaSeconds) override;

private:
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true))
	float Horizontal;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true))
	float Vertical;
};

TutorialAnimInstacne.cpp

void UTutorialAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeUpdateAnimation(DeltaSeconds);

	auto Pawn = TryGetPawnOwner();

	if (IsValid(Pawn))
	{
		auto Character = Cast<ATutorialCharacter>(Pawn);
		if (Character)
		{
			Vertical = Character->MoveForwardValue;
			Horizontal = Character->MoveRightValue;
		}
	}
}

이렇게 수정해주고 난 후 빌드를 해본 뒤 다시 애니메이션 블루프린트 가서

Show Inherited Variables를 체크 해준 뒤

이 변수들이 생겨났다.

이 값들을 가져와서 연결시켜준 후 테스트해보자.

 

잘 되는 것 같다. 그럼 TutorialCharacter 메쉬에 애니메이션 블루프린트를 넣고 실행해보자.

 

잘 되네요.

이제는 Jump Animation을 넣어볼 것이다.

언리얼에서는 IsFalling상태인지 확인하는 형태가 이미 만들어져있다.

그렇기에 그것을 가져와서 점프애니메이션에 적용해보자.

 

TutorialAnimInstance.h

UCLASS()
class FIRSTPROJECT_API UTutorialAnimInstance : public UAnimInstance
{
	GENERATED_BODY()
	
	virtual void NativeUpdateAnimation(float DeltaSeconds) override;

private:

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true))
	bool IsFalling;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true))
	float Horizontal;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true))
	float Vertical;
};

 

TutorialAnimInstance.cpp

#include "FirstProject/Anim/TutorialAnimInstance.h"
#include "GameFramework/PawnMovementComponent.h"
#include <FirstProject\Player\TutorialCharacter.h>

void UTutorialAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeUpdateAnimation(DeltaSeconds);

	auto Pawn = TryGetPawnOwner();

	if (IsValid(Pawn))
	{
		auto Character = Cast<ATutorialCharacter>(Pawn);
		if (Character)
		{
			IsFalling = Character->GetMovementComponent()->IsFalling();
			Vertical = Character->MoveForwardValue;
			Horizontal = Character->MoveRightValue;
		}
	}
}

이제 각 애니메이션을 추가해준다.

이제 조건을 추가해주자.

여기에 조건을 추가해줬다.

IsFalling을 가져오는 방법은 아래와 같다

Time Rmaining은 오른쪽 버튼을 눌러 ratio를 검색해보면 나온다.

 

이제 빌드하고 실행해보고 점프해보자.

 

잘 된다.

 

이렇게 TPS 컨트롤러를 만들어보았다.

 

다음에는 공격하는 것과 점프할 때 움직이지 않는 것을 만들어 보려고 한다.