시작하기 전에
이전 섹션인 캐릭터 무브먼트 환경설정에서 다음 목표를 완료했는지 확인합니다.
입력 액션(Input Actions) 및 입력 매핑 컨텍스트(Mapping Contexts) 작동 방식을 이해했습니다.
캐릭터를 전방, 후방, 왼쪽, 오른쪽 및 점프 무브먼트로 구성했습니다.
1인칭 카메라 컨트롤
카메라 방향을 변경하려면 카메라 트랜스폼(Transform) 프로퍼티의 회전(Rotation) 값을 변경합니다. 3D 공간에서 회전할 때 오브젝트는 피치(Pitch), 롤(Roll), 요(Yaw)를 사용하여 회전 방향과 축을 제어합니다.
피치(Pitch): 가로축(X)을 따라 회전을 제어합니다. 피치를 변경하면 고개를 끄덕이는 것과 비슷하게 오브젝트가 위아래로 회전합니다.
요(Yaw): 세로축(Y)을 따라 회전을 제어합니다. 요를 변경하면 오른쪽 또는 왼쪽으로 회전하는 것과 비슷하게 오브젝트가 왼쪽 또는 오른쪽으로 회전합니다.
롤(Roll): 종방향 축(Z)을 따라 회전을 제어합니다. 롤을 변경하면 고개를 좌우로 기울이는 것과 비슷하게 오브젝트가 좌우로 굴러갑니다.
1인칭 게임의 카메라는 보통 요와 피치를 사용하여 무브먼트를 제어합니다. 비행기나 우주선을 회전시켜야 하거나, 모퉁이에서 훔쳐보는 동작을 시뮬레이션해야 하는 게임을 프로그래밍할 경우 롤이 중요해질 수 있습니다.
블루프린트에서 카메라 무브먼트 살펴보기
BP_FirstPersonCharacter를 열어 블루프린트 에디터에서 디폴트 캐릭터의 카메라 컨트롤 로직을 확인합니다. 이벤트 그래프(EventGraph)에서 Camera Input 노드 그룹의 왼쪽 상단 모서리에 있는 두 개의 노드를 확인합니다.
IA_Move와 마찬가지로 IA_Look 입력 액션에도 Axis2D 값 타입(Axis2D Value Type)이 있으므로 무브먼트를 X 및 Y 값으로 나눕니다. 이번에는 X와 Y가 커스텀 Aim 함수의 요(Yaw) 및 피치(Pitch) 입력이 됩니다.
Aim 함수 노드를 더블클릭하면 내부 로직을 확인할 수 있습니다. Add Controller Yaw Input 및 Pitch Input 함수 노드는 캐릭터에 값을 추가합니다.
1인칭 캐릭터 컴포넌트 살펴보기
BP_FirstPersonCharacter의 뷰포트(Viewport) 탭으로 이동하여 액터와 그 컴포넌트의 3D 프리뷰를 확인합니다.
컴포넌트(Components) 탭에는 월드에서 캐릭터를 정의하는, 붙은 컴포넌트의 구조화된 계층구조가 표시됩니다.
캐릭터 블루프린트는 다음과 함께 자동으로 인스턴스화됩니다.
캐릭터가 월드의 오브젝트와 충돌하게 만드는 캡슐 컴포넌트(Capsule Component).
애니메이션을 활성화하고 캐릭터를 시각화하는 스켈레탈 메시(Skeletal Mesh) 컴포넌트. 디테일(Details) 패널에서 이 캐릭터가
SKM_Manny_Simple을 스켈레탈 메시 에셋으로 사용하는 것을 확인할 수 있습니다.캐릭터를 움직일 수 있게 하는 캐릭터 무브먼트 컴포넌트(Character Movement Component).
이 캐릭터에는 메인 메시 컴포넌트의 자손인 FirstPersonMesh라는 두 번째 스켈레탈 메시(역시 SKM_Manny_Simple 사용)도 있습니다. 1인칭 게임에서 캐릭터는 보통 3인칭 컨텍스트와 1인칭 컨텍스트 모두에 대해 별도의 메시를 갖습니다. 3인칭 메시는 다른 플레이어에게만 표시되거나 플레이어가 3인칭 뷰일 때만 표시됩니다. 1인칭 메시는 플레이어가 1인칭 뷰일 때 표시됩니다.
FirstPersonMesh에는 FirstPersonCamera라는 자손 카메라 컴포넌트가 있습니다. 이 카메라는 플레이어의 1인칭 뷰를 결정하고 캐릭터가 주변을 둘러볼 때 함께 회전합니다. 이 튜토리얼 섹션에서는 C++를 사용하여 런타임에서 캐릭터에 카메라를 인스턴스화하고 이 카메라의 위치와 일치하도록 배치할 것입니다.
캐릭터 컴포넌트에 대한 자세한 내용은 캐릭터 게임플레이 프레임워크 문서를 참조하세요.
코드에서 보기 입력 구현
이 카메라 함수 기능을 코드에서 구현하려면 이전 단계에서 구현한 무브먼트와 마찬가지로 IA_Look 입력 액션을 함수에 바인딩한 다음, 그 함수를 캐릭터에 바인딩하면 됩니다.
Look() 함수와 변수 선언하기
Visual Studio에서 캐릭터의 .h 파일을 엽니다.
이 튜토리얼의 코드 샘플에서는 AdventureCharacter라는 캐릭터 클래스를 사용합니다.
런타임에 캐릭터가 빌드될 때, UE에 동적으로 카메라를 배치하고 카메라 컴포넌트를 추가하라고 알려야 합니다. 이 함수 기능을 활성화하려면 "Camera/CameraComponent.h"에 대한 #include 구문을 새로 추가합니다.
#include "CoreMinimal.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/Character.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "InputActionValue.h"
#include "AdventureCharacter.generated.h"헤더의 protected 섹션에서 LookAction이라는 이름으로 새 UInputAction 포인터를 선언합니다. 이 포인터에 MoveAction 및 JumpAction과 동일한 UPROPERTY() 매크로를 지정합니다. 이는 IA_Look 입력 액션을 가리킵니다.
// Look Input Actions
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
UInputAction* LookAction;public 섹션에서 Value라 명명된, const FInputActionValue 레퍼런스를 받는 Look()이라는 이름으로 새 함수를 선언합니다. 함수에 UFUNCTION() 매크로를 추가했는지 확인합니다.
// Handles Look Input
UFUNCTION()
void Look(const FInputActionValue& Value);Look() 함수를 선언한 다음에 FirstPersonCameraComponent라는 이름으로 새 UCameraComponent 포인터를 선언합니다. 이 프로퍼티를 언리얼 에디터에 노출하려는 경우 디테일 패널의 카메라(Camera) 섹션에 표시되도록 VisibleAnywhere 및 Category = Camera 실행인자와 함께 UPROPERTY() 매크로를 추가합니다.
// First Person camera
UPROPERTY(VisibleAnywhere, Category = Camera)
UCameraComponent* FirstPersonCameraComponent;FirstPersonCameraOffset이라는 이름의 FVector를 선언합니다. 캐릭터를 설정할 때 이 오프셋을 사용하여 카메라 위치를 적절히 배치할 수 있습니다. 다음 값과 EditAnywhere 및 Category = Camera 매크로를 사용하여 이 오프셋을 FVector로 초기화하면 필요할 때 언리얼 에디터에서 조정할 수 있습니다.
// Offset for the first-person camera
UPROPERTY(EditAnywhere, Category = Camera)
FVector FirstPersonCameraOffset = FVector(2.8f, 5.9f, 0.0f);캐릭터 바디와 같이 클로즈업될 오브젝트가 카메라 뷰에 표시되는 방식을 조정하려면 프로퍼티가 한두 개 더 필요합니다. 다음 두 가지 float 변수를 선언합니다.
FirstPersonFieldOfView:FirstPerson태그가 지정된 프리미티브 컴포넌트를 렌더링할 때 이 카메라가 사용할 수평 시야(도 단위)입니다.70.0f로 설정합니다.FirstPersonScale: 카메라가FirstPerson태그가 지정된 프리미티브 컴포넌트에 적용할 스케일입니다.0.6f로 설정합니다.
UPrimitiveComponent는 월드에 물리적으로 존재하는 모든 컴포넌트의 베이스 클래스입니다. 예를 들어, 메시 컴포넌트와 캡슐 컴포넌트는 프리미티브 컴포넌트 타입입니다.
이러한 프로퍼티에 EditAnywhere 및 Category = Camera를 사용하여 UPROPERTY 매크로를 지정합니다.
// First-person primitives field of view
UPROPERTY(EditAnywhere, Category = Camera)
float FirstPersonFieldOfView = 70.0f;
// First-person primitives view scale
UPROPERTY(EditAnywhere, Category = Camera)
float FirstPersonScale = 0.6f;언리얼 엔진은 이러한 카메라 컴포넌트 세팅을 이용해 FirstPerson 태그가 지정된 프리미티브를 다른 월드에서 보는 것과는 다르게 플레이어에게 렌더링함으로써 1인칭 시점에서의 모습과 작동 방식을 최적화할 수 있습니다.
게임에서 FOV가 넓으면 카메라에 가까운 오브젝트(플레이어의 팔, 손에 든 아이템 등)가 너무 크거나 늘어져 보일 수 있는데, 이러한 오브젝트의 FOV를 좁히면 이러한 왜곡 현상을 줄일 수 있습니다. 이러한 오브젝트의 크기를 줄이면 벽으로 튀어나오는 현상을 막을 수 있습니다.
플레이어에게 1인칭 오브젝트와 3인칭 오브젝트를 표시하는 방식을 제어하는 방법에 대한 자세한 내용은 1인칭 렌더링 기능 문서를 참조하세요.
마지막으로, FirstPersonMeshComponent라는 이름의 새 USkeletalMeshComponent 포인터를 선언합니다. 여기에 VisibleAnywhere 및 Category = Mesh 실행인자를 사용하여 UPROPERTY() 매크로를 지정합니다.
// First-person mesh, visible only to the owning player
UPROPERTY(VisibleAnywhere, Category = Mesh)
USkeletalMeshComponent* FirstPersonMeshComponent;이제 다음 항목의 선언 구성을 마쳤습니다.
1인칭 메시(블루프린트에서 본 자손 FirstPersonMesh 메시와 연관됨)
카메라
Look()함수IA_Look입력 액션
이제 캐릭터의 .h 파일은 다음과 같은 모습이어야 합니다.
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/Character.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "InputActionValue.h"
Look()으로 보기 입력 추가
캐릭터의 .cpp 파일을 연 뒤, Look() 함수를 사용하여 캐릭터 블루프린트의 카메라 입력 로직을 구현합니다.
IA_Move와 마찬가지로 IA_Look도 트리거 시 FVector2D 값을 반환합니다. Look()에 대한 새 함수 정의를 추가합니다. 함수 안에서 LookAxisValue라는 이름의 새 FVector2D에서 FInputActionValue의 값을 가져옵니다.
void AAdventureCharacter::Look(const FInputActionValue& Value)
{
const FVector2D LookAxisValue = Value.Get<FVector2D>();
}
그런 다음, if 구문에서 컨트롤러가 유효한지 확인합니다.
컨트롤러가 유효하다면, AddControllerYawInput() 및 AddControllerPitchInput()을 호출하여 각각 LookAxisValue.X 값과 LookAxisValue.Y 값을 전달합니다. 완성된 Look() 함수는 다음과 같은 모습이어야 합니다.
void AAdventureCharacter::Look(const FInputActionValue& Value)
{
const FVector2D LookAxisValue = Value.Get<FVector2D>();
if (Controller)
{
AddControllerYawInput(LookAxisValue.X);
AddControllerPitchInput(LookAxisValue.Y);
}
}SetupPlayerInputComponent로 보기 함수 기능을 입력에 바인딩하기
무브먼트 액션과 비슷하게 SetupPlayerInputComponent() 안에서 Look() 함수를 LookAction 입력 액션에 바인딩합니다.
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AAdventureCharacter::Look);이제 SetupPlayerInputComponent() 함수는 다음과 같은 모습이어야 합니다.
// Called to bind functionality to input
void AAdventureCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
// Check the UInputComponent passed to this function and cast it to an UEnhancedInputComponent
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
{
// Bind Movement Actions
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AAdventurenCharacter::Move);
// Bind Look Actions
코드를 저장하고 Visual Studio에서 Build를 클릭하여 컴파일합니다.
블루프린트에서 룩 입력 액션 할당하기
마지막으로 캐릭터 블루프린트의 새 룩 액션(Look Action) 프로퍼티에 입력 액션을 할당합니다.
캐릭터에 룩 컨트롤을 할당하려면 다음 단계를 따릅니다.
언리얼 에디터에서 캐릭터 블루프린트를 엽니다.
컴포넌트(Components) 패널에서 루트
BP_[CharacterName]컴포넌트가 선택되어 있는지 확인합니다.디테일(Details) 패널의 입력(Input) 섹션에서 룩 액션(Look Action)을
IA_Look으로 설정합니다.블루프린트를 컴파일하고 저장합니다.
보기 무브먼트 테스트하기
플레이(Play)를 눌러 게임을 테스트하면 주변을 둘러보고 원하는 방향으로 캐릭터를 움직일 수 있습니다!
게임 내 시점이 1인칭 카메라에서 나오는 것처럼 보이지만, 실제로는 아직 캐릭터에 카메라 컴포넌트가 없다는 점에 유의하세요. 대신, 언리얼 엔진은 캐릭터의 캡슐 컴포넌트 중앙에서 바라본 뷰를 시뮬레이션합니다. 다음 단계에서는 캐릭터 클래스에 카메라를 추가하여 이를 변경하는 방법을 알아보겠습니다.
런타임에 컴포넌트 생성하기
다음으로 헤더 파일에서 선언한 FirstPersonCameraComponent 및 FirstPersonMeshComponent 포인터를 인스턴스화하여 캐릭터의 1인칭 메시와 카메라 생성을 완료합니다.
시작하려면 캐릭터의 .cpp 파일을 엽니다.
파일 맨 위에는 이 튜토리얼에서는AAdventureCharacter()인 클래스 생성자가 있습니다. 이 클래스는 오브젝트가 메모리에 할당될 때 실행되며 캐릭터의 디폴트 값을 설정합니다. 여기에 추가 컴포넌트를 추가할 수 있습니다.
클래스 생성자 또는 BeginPlay()에 코드를 추가할 때는 액터의 라이프사이클에서 각각 언제 실행되며 다른 오브젝트가 아직 초기화되지 않았는지를 고려하세요.
클래스 생성자가 실행될 때, 다른 컴포넌트나 액터가 아직 존재하지 않을 수 있습니다. BeginPlay()는 게임플레이가 시작되거나 액터가 스폰될 때 실행되므로 액터와 모든 컴포넌트가 완전히 초기화되어 등록되며, 여기서 다른 액터를 참조해도 안전합니다.
또한 언리얼 엔진이 내부에서 어태치먼트, 피직스, 네트워킹 또는 부모-자식 관계의 타이밍을 처리하는 방식 때문에 일부 작업은 기술적으로 더 일찍 수행할 수 있더라도 BeginPlay()에서 수행할 때 더 안정적으로 작동합니다.
카메라 컴포넌트 생성하기
캐릭터에 컴포넌트를 추가하려면 CreateDefaultSubobject() 템플릿 함수를 사용합니다. 이 함수는 새 컴포넌트에 포인터를 반환하고 다음 실행인자를 받습니다.
CreateDefaultSubobject<type>(TEXT("Name"));
여기서 type은 생성하는 서브오브젝트의 타입이고, Name은 언리얼 엔진이 서브오브젝트를 식별하고 에디터에 표시하는 데 사용하는 내부 이름입니다.
클래스 생성자에서 FirstPersonCameraComponent 포인터를 UCameraComponent 타입의 CreateDefaultSubobject() 호출 결과로 설정합니다. TEXT 실행인자에서 오브젝트의 이름을 "FirstPersonCamera"로 지정합니다.
FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));이렇게 하면 디폴트 카메라 오브젝트가 캐릭터(Character) 클래스의 자손으로 생성됩니다. 그런 다음, 카메라가 제대로 인스턴스화되었는지 확인하기 위해 FirstPersonCameraComponent가 null이 아닌지 확인합니다.
// Create a first person camera component.
FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
check(FirstPersonCameraComponent != nullptr);메시 컴포넌트 생성하기
FirstPersonMeshComponent를 또 다른 CreateDefaultSubobject 함수 호출에 설정합니다. 이번에는 USkeletalMeshComponent를 타입으로, 'FirstPersonMesh'를 이름으로 사용합니다. 그 후에 잊지 말고 check를 추가해야 합니다.
// Create a first person mesh component for the owning player.
FirstPersonMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
check(FirstPersonMeshComponent != nullptr);메시 어태치 및 환경설정
이제 메시가 생성되었으니 캐릭터에 어태치하고 1인칭 렌더링을 활성화합니다.
SetupAttachment() 함수는 하나의 씬 컴포넌트를 다른 컴포넌트에 어태치하여 컴포넌트 계층구조에서 부모-자손 관계를 설정합니다.
FirstPersonMeshComponent가 가리키는 오브젝트에서 SetupAttachment() 함수를 호출하고 부모 컴포넌트에 전달합니다. 이 경우, 부모는 GetMesh()를 사용하여 얻을 수 있는 캐릭터의 디폴트 스켈레탈 메시여야 합니다.
// Attach the FirstPerson mesh to the Skeletal Mesh
FirstPersonMeshComponent->SetupAttachment(GetMesh());캐릭터의 헤더 파일에서 카메라에 가까운 컴포넌트에 사용할 카메라 필드 오브 뷰와 카메라 스케일을 선언했습니다. 이러한 카메라 프로퍼티를 1인칭 메시에 적용하려면 메시의 FirstPersonPrimitiveType 프로퍼티를 FirstPerson으로 설정합니다.
FirstPersonMeshComponent->FirstPersonPrimitiveType = EFirstPersonPrimitiveType::FirstPerson;FirstPerson 타입의 프리미티브는 별도의 렌더 패스에서 렌더링되며 주로 다른 카메라 파라미터를 사용하므로 그림자를 드리우지 않습니다. 플레이어 그림자는 3인칭 메시에서 드리울 때 가장 원활히 작동하는데, 다음 섹션에서 이 부분을 설정하겠습니다.
메시 가시성 설정
지금까지 게임플레이 중에 오버랩될 캐릭터의 1인칭 및 3인칭 스켈레탈 메시를 설정했습니다. 단, 1인칭 메시는 다른 플레이어에게는 보이지 않아야 하고 3인칭 메시는 플레이어인 본인에게는 보이지 않아야 합니다.
1인칭 및 3인칭 메시와 그림자의 가시성을 환경설정하려면 다음 단계를 따르세요.
캐릭터의 클래스 생성자에서, 1인칭 메시의 프리미티브 타입을 설정한 뒤, 3인칭 메시 컴포넌트의
FirstPersonPrimitiveType을WorldSpaceRepresentation으로 설정합니다.C++GetMesh()->FirstPersonPrimitiveType = EFirstPersonPrimitiveType::WorldSpaceRepresentation;이 프리미티브 타입은 다른 플레이어에게 보이는 컴포넌트용입니다. 이는 해당 컴포넌트의
OwnerNoSee프로퍼티를 자동으로false로 설정하므로 자기 자신에게는 보이지 않습니다. 하지만 메시는 여전히 그림자를 드리웁니다.BeginPlay()에서, 글로벌 엔진 포인터 검사가 끝난 뒤,FirstPersonMeshComponent에서SetOnlyOwnerSee()를 호출하고true를 전달하여 1인칭 메시가 소유한 플레이어에게만 보이도록 합니다.C++// Only the owning player sees the first-person mesh FirstPersonMeshComponent->SetOnlyOwnerSee(true);
카메라 컴포넌트 어태치하기
캐릭터의 클래스 생성자에서, 또 다른 SetupAttachment() 호출을 사용하여 카메라 컴포넌트를 1인칭 메시에 붙입니다. 이번에는 컴포넌트가 붙을 메시의 정확한 위치(소켓)를 지정하는 선택적 오버로드를 추가합니다.
이 튜토리얼에서 사용된 SKM_Manny_Simple 메시에는 애니메이션에 쓰이는 프리셋 소켓(또는 본) 컬렉션이 있습니다. 코드에서 FName 스트링을 사용하여 소켓을 참조할 수 있습니다. 카메라를 캐릭터의 머리 근처에 배치하는 것이 가장 좋으므로 SetupAttachment에 Head 소켓 이름을 전달하여 카메라를 해당 소켓에 붙입니다. 나중에 카메라를 캐릭터의 눈 가까이로 이동할 것입니다.
FName은 특별한 유사 스트링 타입으로, 언리얼 엔진에서 메모리 효율적인 방식으로 고유하고 불변하는 이름을 저장하는 데 사용됩니다.
// Attach the camera component to the first-person Skeletal Mesh.
FirstPersonCameraComponent->SetupAttachment(FirstPersonMeshComponent, FName("head"));소켓의 정의와 생성 방법에 대한 자세한 내용은 스켈레탈 메시 소켓을 참조하세요.
카메라 환경설정하기
카메라 컴포넌트를 초기화할 때, 카메라를 캐릭터의 헤드 소켓에 붙였습니다. 하지만 카메라는 캐릭터의 눈에 위치했을 때 더 정확하게 보입니다. 카메라도 기본적으로 아래를 향하고 있으므로 캐릭터의 머리 뒤에서 회전시켜야 합니다.
카메라를 제자리로 이동하고 회전하려면 SetRelativeLocationAndRotation()을 호출하여 FirstPersonCameraOffset과 (0.0f, 90.0f, -90.0f)로 설정된 새로운 FRotator를 전달합니다.
// Position the camera slightly above the eyes and rotate it to behind the player's head
FirstPersonCameraComponent->SetRelativeLocationAndRotation(FirstPersonCameraOffset, FRotator(0.0f, 90.0f, -90.0f));게임플레이 중에 카메라가 캐릭터와 함께 회전하도록 하려면 FirstPersonCameraComponent의 bUsePawnControlRotation 프로퍼티를 true로 설정합니다. 이렇게 하면 카메라가 부모 폰으로부터 회전을 상속하여 캐릭터가 회전할 때 카메라도 따라갑니다.
// Enable the pawn to control camera rotation.
FirstPersonCameraComponent->bUsePawnControlRotation = true;마지막으로, 카메라에 1인칭 필드 오브 뷰 및 1인칭 스케일 렌더링을 추가합니다. 컴포넌트의 bEnableFirstPersonFieldOfView 프로퍼티와 bEnableFirstPersonScale 프로퍼티를 true로 설정합니다. 그런 다음, 앞서 선언한 디폴트 FOV 및 스케일 값을 지정합니다.
// Enable first-person rendering and set default FOV and scale values
FirstPersonCameraComponent->bEnableFirstPersonFieldOfView = true;
FirstPersonCameraComponent->bEnableFirstPersonScale = true;
FirstPersonCameraComponent->FirstPersonFieldOfView = FirstPersonFieldOfView;
FirstPersonCameraComponent->FirstPersonScale = FirstPersonScale;
캐릭터의 생성자는 다음과 같은 모습이어야 합니다.
// Sets default values
AAdventureCharacter::AAdventureCharacter()
{
// 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;
// Create a first person camera component
FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
check(FirstPersonCameraComponent != nullptr);
코드를 저장하고 Visual Studio에서 Build 클릭하여 컴파일합니다.
언리얼 에디터에서 메시 할당하기
카메라 컨트롤은 구성했지만, 아직 한 단계가 더 남았습니다. 에디터를 사용하여 코드에서 선언한 변수에 스켈레탈 메시 에셋을 추가해야 합니다.
스켈레탈 메시를 캐릭터 블루프린트에 추가하려면 다음 단계를 따릅니다.
아직 열리지 않았을 경우, 언리얼 에디터에서 캐릭터 블루프린트를 엽니다.
컴포넌트(Components) 패널에서 루트 BP_[CharacterName]이 선택되어 있는지 확인합니다.
디테일(Details) 패널의 메시(Mesh) 섹션에서 캐릭터의 스켈레탈 메시 에셋 슬롯(SkeletalMeshAsset)이 하나가 아니라 두 개인데, 이는 코드에
FirstPersonMeshComponent를 생성했기 때문입니다. 각 프로퍼티의 드롭다운 메뉴에서 화살표를 클릭하고 두 메시 모두에 대해SKM_Manny_Simple을 선택합니다.FirstPersonMeshComponent를 설정하면 카메라가 캐릭터의 머리 뒤 위치로 이동해야 합니다.
블루프린트를 저장하고 컴파일(Compile)을 클릭합니다.
게임을 플레이하다가 아래를 내려다보면 캐릭터의 1인칭 메시가 보여야 합니다! 주위를 둘러보면 이에 맞춰 메시가 회전하며, 카메라도 무브먼트에 따라서 움직일 것입니다. 3인칭 메시는 런타임에 숨겨지고 다른 플레이어만 볼 수 있습니다. 하지만, 캐릭터는 여전히 스태틱 T-포즈 상태입니다. 그럼 애니메이션 블루프린트를 사용하여 캐릭터에 애니메이션을 추가하고 생동감을 불어넣어 봅시다!
캐릭터에 애니메이션 추가하기
UAnimInstance 클래스의 인스턴스를 통해 코드에서 애니메이션 로직에 액세스할 수 있습니다. 이 컨트롤러는 스테이트 및 기타 변수에 따라 스켈레탈 메시에서 블렌딩하고 재생할 애니메이션을 결정합니다. 애니메이션 블루프린트 역시 UAnimInstance에서 파생되며, C++에서 UAnimBlueprint 타입으로 참조할 수 있습니다.
애님 인스턴스(Anim Instance) 클래스 빌드는 이 튜토리얼의 범위를 벗어납니다. 대신 사전 빌드한 1인칭 템플릿의 애니메이션 블루프린트를 캐릭터에 추가합니다. 이 블루프린트에는 캐릭터가 다양한 무브먼트와 유휴 애니메이션을 재생하는 데 필요한 애니메이션과 로직이 포함되어 있습니다.
언리얼 엔진의 애니메이션은 메시 단위로 설정되므로 1인칭 메시와 3인칭 메시 모두 별도의 애니메이션이 필요합니다. 게임이 시작되면 3인칭 메시가 숨겨지므로 1인칭 메시에만 애니메이션을 설정하면 됩니다.
캐릭터에 애니메이션 프로퍼티와 애니메이션 블루프린트를 추가하려면 다음 단계를 따릅니다.
캐릭터의
.h파일 상단에서UAnimBlueprint클래스를 포워드 선언합니다. 이 클래스는 프로젝트의 애니메이션 블루프린트를 나타냅니다.C++class UAnimBlueprint; class UInputMappingContext; class UInputAction; class UInputComponent;그런 다음
public섹션에서FirstPersonDefaultAnim이라는 이름으로 새UAnimBlueprint포인터를 선언합니다.EditAnywhere및Category = Animation으로UCLASS()매크로를 지정합니다.C++// First Person animations UPROPERTY(EditAnywhere, Category = Animation) UAnimBlueprint* FirstPersonDefaultAnim;캐릭터
.cpp파일의BeginPlay()에서FirstPersonMeshComponent->SetAnimInstanceClass()를 호출합니다. 코드에 애님 인스턴스 클래스를 정의하지 않았더라도,GeneratedClass를 사용하여 애니메이션 블루프린트에서 클래스를 생성할 수 있습니다.C++// Only the owning player sees the first person mesh. FirstPersonMeshComponent->SetOnlyOwnerSee(true); // Set the animations on the first person mesh. FirstPersonMeshComponent->SetAnimInstanceClass(FirstPersonDefaultAnim->GeneratedClass);코드를 저장하고 Visual Studio에서 컴파일합니다.
언리얼 에디터에서 캐릭터(Character) 블루프린트를 다시 열고 루트 BP_[CharacterName] 컴포넌트를 선택합니다.
디테일(Details) 패널의 애니메이션(Animation) 아래에서 1인칭 디폴트 애님(First Person Default Anim)을
ABP_Unarmed로 설정합니다.블루프린트를 저장하고 컴파일합니다.
캐릭터 테스트하기
플레이(Play)를 눌러 게임을 테스트합니다. 아래를 내려다보면 움직일 때마다 1인칭 메시가 애니메이팅 되는 것을 볼 수 있습니다! 이동하고 점프하면서 이 블루프린트로 제어되는 다양한 애니메이션을 확인해 보세요.
다음 순서
다음 섹션에서는 캐릭터가 집어 들고 사용할 아이템을 만드는 방법을 알아보겠습니다!
아이템 및 데이터 관리
아이템 데이터 구조체(Item Data Structs), 데이터 에셋(Data Assets) 및 데이터 테이블(Data Tables)을 사용하여 아이템을 정의하고 엔진 퀄리티를 위해 아이템 데이터를 저장하고 정리하는 방법을 알아봅니다.
완성된 코드
이 섹션에서 빌드한 완성된 코드는 다음과 같습니다.
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/Character.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "InputActionValue.h"
#include "AdventureCharacter.h"
// Sets default values
AAdventureCharacter::AAdventureCharacter()
{
// 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;
// Create a first-person camera component
FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));