블루프린트 없이 C++로 폰과 캐릭터 만들기(1)

유영준·2023년 1월 3일
0
post-thumbnail

오늘은 폰과 캐릭터의 차이를 보고, 폰과 캐릭터로 각각 플레이어 캐릭터를 만들어보겠다

순서는

  • 폰과 캐릭터의 차이
  • 폰으로 만든 플레이어
  • 캐릭터로 만든 플레이어

이다

폰과 캐릭터의 차이

폰과 캐릭터는 모두 언리얼 엔진에서 제공하는 액터이고 폰은 유저가 컨트롤하는 물체,
캐릭터는 폰을 상속받아 움직이는 캐릭터형 액터이다

그렇기 때문에 캐릭터는 기본적으로 충돌을 체크해주는 CapsuleComponent, 뼈대를 이루는 SkeletalMesh,
이동을 제어하는 CharacterMovement 컴포넌트를 보유하고 있다

  • UE5에서는 중력의 영향을 받지 않는 FloatingPawnMovement 와 중력의 영향을 받는 CharacterMovement
    2가지 이동방식을 제공한다

폰으로 만든 플레이어

먼저 오늘 필요한 에셋은 모델링애니메이션에서 받을 수 있다
애니메이션은 resource폴더의 chapter5 폴더 안에 있다

모델링은 에픽런처를 통해 import 해주면 되고, 애니메이션은 컨텐츠 브라우저 창에 import 기능을 통해 추가해주자

블루프린트 없이도 애니메이션을 실행 시킬 수 있지만, 편의를 위해 이번 한번만 블루프린트를 쓰도록 하겠다

우클릭 후 Animation -> Animation BluePrint 를 통해 애니메이션 블루프린트를 만들어주고 이름을 짓는다

블루프린트를 열어 오른쪽 하단에 warriorRun 애니메이션을 블루프린트 창으로 끌어다 놓는다

이후 사람 모양을 이어주면 완성된다

현재는 이동여부와 관계없이 일단은 이동하는 것에 초점을 둘 것이다
Loop Animation이 체크되어 있지 않다면 체크하는것을 잊지 말자

마지막으로 컴파일 후 저장을 하게 되면 움직이고 있는 캐릭터의 모습을 볼 수 있다


이제 실제로 폰이 움직이게끔 해보자

폰에게 캡슐, 스켈레톤 메쉬, 무브먼트, 카메라암, 카메라를 컴포넌트로 달아주도록 하겠다
캐릭터는 기본적으로 CharacterMovement 가 있으니 폰은 FloatingPawnMovement를 달아주도록 하겠다

먼저 헤더를 추가해주고

각각의 컴포넌트를 추가 시켜 주었다

아래는 cpp파일에서의 선언이다
1일차와 2일차에 했던 선언 과정을 동일하게 수행해준다

*워리어 모델링은 원하는 것을 아무거나 해도 상관이 없다

AABPawn::AABPawn()
{
	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	Capsule   = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CAPSULE"));
	Mesh      = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MESH"));
	Movement  = CreateDefaultSubobject<UFloatingPawnMovement>(TEXT("MOVEMENT"));
	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SPRINGARM"));
	Camera    = CreateDefaultSubobject<UCameraComponent>(TEXT("CAMERA"));

	RootComponent = Capsule;
	Mesh     ->SetupAttachment(Capsule);
	SpringArm->SetupAttachment(Capsule);
	Camera   ->SetupAttachment(SpringArm);

	Capsule  ->SetCapsuleHalfHeight(80.0f);
	Capsule  ->SetCapsuleRadius(34.0f);
	Mesh     ->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, -88.0f), FRotator(0.0f, -90.0f, 0.0f));
	SpringArm->TargetArmLength = 400.0f;
	SpringArm->SetRelativeRotation(FRotator(-15.0f, 0.0f, 0.0f));

	Mesh->SetAnimationMode(EAnimationMode::AnimationBlueprint);

	static ConstructorHelpers::FClassFinder<UAnimInstance> WARRIOR_ANIM
	(TEXT("/Game/InfinityBladeWarriors/Character/Animations/WarriorAnimBlueprint.WarriorAnimBlueprint_C"));

	if (WARRIOR_ANIM.Succeeded())
		Mesh->SetAnimInstanceClass(WARRIOR_ANIM.Class);

	static ConstructorHelpers::FObjectFinder<USkeletalMesh> SK_CARDBOARD
	(TEXT("/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Cardboard.SK_CharM_Cardboard"));

	if (SK_CARDBOARD.Succeeded())
		Mesh->SetSkeletalMesh(SK_CARDBOARD.Object);

}

여기까지 왔다면 이제 게임 실행 시 움직이는 모션을 가진 캐릭터가 나오게 된다
다만 아직 입력을 받아 움직이지는 못하는 상황이다
입력을 받기 위해 Edit - project setting - input으로 가자
Axis Mapping 에서 원하는 w,s는 앞뒤, a,d 는 좌우로 움직이도록 매핑을 설정해준다

헤더 파일에 매핑한 이름과 동일한 함수를 만들고, 이를 cpp 상에 선언해준다

이동과 관련된 요소의 바인딩은 SetupPlayerInputController 함수에 추가를 해주면 된다
BindAxis 를 통해 바인딩을 할 수 있다

이후 선언해준 UpDown 함수와 LeftRight 함수에는 AddMovement 함수를 통해 이동을 구현해준다

GetActorForwardVector 는 액터의 정면방향을 리턴해준다
좌우 이동에는 오른쪽 방향을 리턴해주는 GetActorRightVector 를 사용한다

여기까지 왔다면 이동하는 캐릭터를 볼 수 있다


에디터에서 플레이 버튼을 누를 때마다 게임 화면을 클릭해야 입력이 되는 것이 불편하다면
간단한 코드를 ABPlayerController 클래스에 추가해주도록 하자

헤더에서 BeginPlay 함수를 재정의해주고

cpp 파일에서 선언을 해주자

게임을 시작하면 마우스가 기본적으로 게임 안에 들어가 있는 상태가 된다


캐릭터로 만든 플레이어

캐릭터는 기본적으로 Capsule, ASkeletalMesh, CharacterMovement 컴포넌트를 보유하고 있다
따라서 이들의 컴포넌트는 추가해줄 필요가 없고, 다만 Get~ 함수를 써서 인자를 받아오면 된다

아래는 h파일의 선언부이다

추가적으로 마우스의 회전을 받는 Turn 함수와 LookUp 함수를
Input창에서 만든 후 추가해 주도록 하자

아래는 cpp 파일의 선언부이다

// Sets default values
AABCharacter::AABCharacter()
{
	// 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);

	GetMesh()->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, -88.0f), FRotator(0.0f, -90.0f, 0.0f));
	SpringArm->TargetArmLength = 400.0f;
	SpringArm->SetRelativeRotation(FRotator(-15.0f, 0.0f, 0.0f));

	GetMesh()->SetAnimationMode(EAnimationMode::AnimationBlueprint);

	static ConstructorHelpers::FClassFinder<UAnimInstance> WARRIOR_ANIM
	(TEXT("/Game/InfinityBladeWarriors/Character/Animations/WarriorAnimBlueprint.WarriorAnimBlueprint_C"));

	if (WARRIOR_ANIM.Succeeded())
		GetMesh()->SetAnimInstanceClass(WARRIOR_ANIM.Class);

	static ConstructorHelpers::FObjectFinder<USkeletalMesh> SK_CARDBOARD
	(TEXT("/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Cardboard.SK_CharM_Cardboard"));

	if (SK_CARDBOARD.Succeeded())
		GetMesh()->SetSkeletalMesh(SK_CARDBOARD.Object);
}

입력받은 회전값을 통해 액터가 회전하게 하는 함수는 AddControllerInput이다
각각 x축 회전을 받는 pitch, Y축 회전을 받는 yaw, z축 회전을 받는 roll이다

이제 마지막으로 GameMode에서 DefaultPawnClass를 캐릭터로 바꿔준다

*이때 캐릭터 헤더를 추가하는 것을 잊지말자


profile
토비폭스가 되고픈 게임 개발자

0개의 댓글