폰을 조작하기 위해 프로젝트의 입력을 설정하고,
입력 값을 폰의 움직임으로 변환하는 폰 무브먼트 컴포넌트를 사용한다.
애니메이션 블루프린트를 사용해 애니메이션을 불어넣는 법을 학습한다.
<1>. 폰의 구성 요소
폰은 여러 가지 형태가 될 수 있지만, 여기서는 인간형 폰을 제작한다.
※인간형 폰을 제작하기 위해 고려할 요소들
- 시각적 요소 : 스켈레탈 메시
- 충돌 요소 : 캡슐 컴포넌트
- 움직임 요소 : 폰 무브먼트 컴포넌트
- 내비게이션 : 스스로 길 찾기 기능
- 카메라 출력 : 폰을 화면에 전송
마켓플레이스에서 임포트한 에셋을 추가하고 C++ 코드를 사용해 폰을 제작한다. 위의 요소를 바탕으로 5개의 컴포넌트를 사용한다.
- SkeletalMesh (시각적 요소)
- Capsule (충돌 요소) - 움직임을 담당할 예정이므로 루트 컴포넌트로 설정
- FloatingPawnMovement (움직임 요소)
- SpringArm (카메라 구도)
- Camera (카메라 출력)
<2>. 폰의 조작
폰을 움직이기 위해 폰에 입력에 대한 처리 로직, 폰 무브먼트를 설정해 본다.
<2> - 1. 입력하기
프로젝트 세팅 > 입력 > Bindings > Action Mappings / Axis Mappings
※ Axis Mappings : 조이스틱의 레버 / 꾹 누르면 지속적인 신호 전달
Action Mappings : 조이스틱의 버튼 / 누르고 뗄 때만 신호를 전달
-언리얼에서는 MoveForward, MoveRight 같은 3인칭 입력 설정이 이미 만들어져 있다.
<2> - 2. 입력 신호를 받아들이기 - MoveForward, MoveRight를 직접 만들어보는 과정
입력 설정이 완료되면, 게임 로직에서 입력을 사용하도록 코드를 작성한다 → 언리얼 엔진은 입력 설정을 처리하기 위해 'InputComponent'라는 언리얼 오브젝트를 제공한다 → 이를 사용해 폰과 입력 설정을 연결하면, 자동으로 입력 신호는 폰의 멤버 함수의 인자로 전달된다 → 이를 연결하는 곳이 폰의 'SetupInputComponent' 함수이다.
InputComponent는 BindAxis, BindAction 2가지 함수를 제공한다. 먼저 레버 신호를 받아보자.
→ BindAxis 함수를 이용해 '입력 설정의 이름'과 이와 연동할 '언리얼 오브젝트 인스턴스의 함수 포인터'를 지정한다.
//ABPawn.h
class ARENABATTLE_API AABPawn : public APawn
{
GENERATED_BODY)
...
private:
void UpDown(float NewAxisValue);
void LeftRight(float NewAxisValue);
}
//ABPawn.cpp
void AABPawn::SetupPlayerInputComponent(UInputComponent *PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis(TEXT("UpDown"), this, &AABPawn::UpDown);
PlayerInputComponent->BindAxis(TEXT("LeftRight"), this, &AABPawn::LeftRight);
}
void AABPawn::UpDown(float NewAxisValue)
{
ABLOG(Warning, TEXT("%f"), NewAxisValue);
}
입력 값이 제대로 전달되는지 확인하기 위해 LOG를 출력해 본다. 출력이 잘 되었다면, 이를 폰의 움직임으로 활용해야 한다 →이때 사용하는 것이 폰 무브먼트 컴포넌트의 'AddMovementInput' 함수이다.
<2> - 3. 입력 값을 움직임으로 나타내기 - AddMovementInput 함수 사용
AddMovementInput에는 이동향 방향을 WorldDirection에 지정해야 한다. 이는 'GetActorForwardVector'함수를 사용해 가져올 수 있다.
void AddMovementInput(FVector WorldDirection, float ScaleValue = 1.0f, bool bForce = false);
//ABPawn.cpp
void AABPawn::UpDown(float NewAxisValue)
{
AddMovementInput(GetActorForwardVector(), NewAxisValue);
}
void AABPawn::LeftRight(float NewAxisValue)
{
AddMovementInput(GetActorRightVector(), NewAxisValue);
}
※ AddMovementInput 명령을 사용해 폰을 상하좌우로 조종하는 코드
<3>. 애니메이션의 설정
위에서 한 대로 설정하고 플레이 버튼을 누르면 팔 벌린 자세로 정지한 폰이 등장한다. 이를 보완하기 위해 스켈레탈 메시에 애니메이션을 설정한다.
코드로 애니메이션을 지정하는 방법이 있지만, 이는 비효율적이므로 블루프린트를 사용한 구현방법을 다루겠다.
- 애니메이션 블루프린트 에셋을 생성한다.
- 블루프린트와 연결되는 캐릭터 스켈레톤 에셋을 지정한다.
- 에셋 브라우저에서 사용할 애니메이션(Run)을 애님 그래프에 끌어다 놓는다.
- Run 애니메이션의 사람 모양의 핀을 최종 애니메이션 노드에 연결한다.
- 애니메이션 블루프린트 에셋의 경로를 복사하여 스켈레탈 메시 컴포넌트에 등록한다.
- 이러한 애니메이션 블루프린트는 c++ 프로그래밍의 '애님 인스턴스'라는 클래스로 관리된다.
- 스켈레탈 메시 컴포넌트는 자신이 관리하는 캐릭터의 애니메이션을 이 애님 인스턴스에 위임하는 구조이다
→ 블루프린트 에셋의 클래스 정보를 애님 인스턴스 속성에 지정해줘야 한다.
→ 경로를 복사하여 '_C'를 추가로 붙여 클래스 정보를 가져온다.
※ 클래스에 '_C'를 붙이면 블루프린트 클래스 버전이다.
//ABPawn.cpp
#include "ABPawn.h"
AABPawn::AABPawn()
{
...
Mesh->SetAnimationMode(EAnimationMode::AnimationBlueprint);
static ConstructorHelpers::FClassFinder<UAnimInstance>WARRIOR_ANIM(TEXT(
"Game/Book/Animations/WarriorAnimBlueprint.WarriorAnimBlueprint_C"));
if(WARRIOR_ANIM.Succeeded())
{
Mesh->SetAnimInstanceClass(WARRIOR_ANIM.Class):
}
}
'게임 개발 > 이득우의 언리얼 C++' 카테고리의 다른 글
[이득우의 언리얼 C++ 게임개발의 정석] #7. 애니메이션 시스템의 설계 (0) | 2024.06.17 |
---|---|
[이득우의 언리얼 C++ 게임개발의 정석] #6. 캐릭터의 제작과 컨트롤 (0) | 2024.06.13 |
[이득우의 언리얼 C++ 게임개발의 정석] #4. 게임플레이 프레임워크 (0) | 2024.06.10 |
[이득우의 언리얼 C++ 게임개발의 정석] #3. 움직이는 액터의 제작 (1) | 2024.06.08 |
[이득우의 언리얼 C++ 게임개발의 정석] #2. 액터의 설계 (0) | 2024.06.07 |