- 간단한 플레이어 캐릭터를 C++로 생성하기
- 플레이어 컨트롤러를 추가하고, 기본으로 설정하기
- 기본적인 입력 추가하기 (상하좌우 이동 및 화면 전환)
MMPlayerController Class
- 지금은 생성만 하고 GameMode에 등록해주도록 합니다.
// MMPlayerController Header
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MMPlayerController.generated.h"
/**
*
*/
UCLASS()
class MYSTICMAZE_API AMMPlayerController : public APlayerController
{
GENERATED_BODY()
};
// MMGameMode CPP
AMMGameMode::AMMGameMode()
{
...
// PlayerControllerClass 설정
static ConstructorHelpers::FClassFinder<APlayerController> ControllerClassRef(TEXT("/Script/CoreUObject.Class'/Script/MysticMaze.MMPlayerController'"));
if (ControllerClassRef.Succeeded())
{
PlayerControllerClass = ControllerClassRef.Class;
}
}
- 언리얼 5.1버전부터 향상된 입력(Enhanced Input)이 기본으로 설정되어 있습니다.
- 향상된 입력을 사용해 플레이어의 이동을 구현해보도록 하겠습니다.
[향상된 입력 문서]
프로젝트에서 사용할 입력 버전은 크게 3가지로 나뉩니다.
우선 기본 상태의 이동을 구현해보도록 하겠습니다.
입력 액션을 추가합니다. (BasicMove, BasicLook)
입력 매핑 컨텍스트를 추가합니다. (IMC_BasicPlayer)
MMPlayerCharacter Class
- 위에서 생성한 IA와 IMC를 찾아 등록하고, 함수를 매핑하여 실제로 동작하도록 구현해보도록 하겠습니다.
// MMPlayerCharacter Header
#include "InputActionValue.h"
...
UCLASS()
class MYSTICMAZE_API AMMPlayerCharacter : public AMMCharacterBase
{
GENERATED_BODY()
...
// Input Section
protected:
// 입력에 따라 매핑될 함수를 선언합니다.
void BasicMove(const FInputActionValue& Value);
void BasicLook(const FInputActionValue& Value);
UPROPERTY(VisibleAnywhere, Category = Input, Meta = (AllowPrivateAccess = "true"))
TObjectPtr<class UInputMappingContext> IMC_Basic;
UPROPERTY(VisibleAnywhere, Category = Input, Meta = (AllowPrivateAccess = "true"))
TObjectPtr<class UInputAction> IA_BasicMove;
UPROPERTY(VisibleAnywhere, Category = Input, Meta = (AllowPrivateAccess = "true"))
TObjectPtr<class UInputAction> IA_BasicLook;
};
// MMPlayerCharacter CPP
#include "Character/MMPlayerCharacter.h"
#include "Components/CapsuleComponent.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "InputAction.h"
#include "InputMappingContext.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
AMMPlayerCharacter::AMMPlayerCharacter()
{
...
// Input
{
static ConstructorHelpers::FObjectFinder<UInputMappingContext>IMC_BasicRef(TEXT("/Script/EnhancedInput.InputMappingContext'/Game/MysticMaze/Player/Control/IMC_BasicPlayer.IMC_BasicPlayer'"));
if (IMC_BasicRef.Object)
{
IMC_Basic = IMC_BasicRef.Object;
}
static ConstructorHelpers::FObjectFinder<UInputAction>IA_BasicMoveRef(TEXT("/Script/EnhancedInput.InputAction'/Game/MysticMaze/Player/Control/InputAction/IA_BaseMove.IA_BaseMove'"));
if (IA_BasicMoveRef.Object)
{
IA_BasicMove = IA_BasicMoveRef.Object;
}
static ConstructorHelpers::FObjectFinder<UInputAction>IA_BasicLookRef(TEXT("/Script/EnhancedInput.InputAction'/Game/MysticMaze/Player/Control/InputAction/IA_BaseLook.IA_BaseLook'"));
if (IA_BasicLookRef.Object)
{
IA_BasicLook = IA_BasicLookRef.Object;
}
}
// Setting (기본적으로 원하는 기본 이동을 위한 캐릭터 설정)
{
// 컨트롤러의 Rotation에 영향 X
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// 폰의 컨트롤 회전 사용
SpringArm->bUsePawnControlRotation = true;
// 움직임에 따른 회전 On
GetCharacterMovement()->bOrientRotationToMovement = true;
}
}
void AMMPlayerCharacter::BeginPlay()
{
Super::BeginPlay();
APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (PlayerController && IMC_Basic)
{
// 서브시스템 불러오기
if (UEnhancedInputLocalPlayerSubsystem* SubSystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
// 매핑 컨텍스트 추가
SubSystem->AddMappingContext(IMC_Basic, 0);
// 입력 시작
EnableInput(PlayerController);
}
}
}
void AMMPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// 향상된 입력 컴포넌트로 형변환
// * CastChecked : 캐스팅이 실패할 경우 프로그램을 중단시키는 대신 에러 메시지 출력
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);
// 생성된 IA_BasicLook, IA_BasicMove와 함수 매핑
EnhancedInputComponent->BindAction(IA_BasicLook, ETriggerEvent::Triggered, this, &AMMPlayerCharacter::BasicLook);
EnhancedInputComponent->BindAction(IA_BasicMove, ETriggerEvent::Triggered, this, &AMMPlayerCharacter::BasicMove);
}
void AMMPlayerCharacter::BasicMove(const FInputActionValue& Value)
{
// 입력받은 Value로부터 MovementVector 가져오기
FVector2D MovementVector = Value.Get<FVector2D>();
// 컨트롤러의 회전 중 Yaw(Z)를 가져와 저장
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// 회전(Yaw)을 기반으로 전방 및 오른쪽 방향을 받아오기 (X : 전방, Y : 오른쪽)
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// Movement에 값 전달 (방향, 이동량)
AddMovementInput(ForwardDirection, MovementVector.X);
AddMovementInput(RightDirection, MovementVector.Y);
}
void AMMPlayerCharacter::BasicLook(const FInputActionValue& Value)
{
// 입력받은 Value로부터 LookVector 가져오기
FVector2D LookVector = Value.Get<FVector2D>();
// Controller에 값 전달
AddControllerYawInput(LookVector.X);
AddControllerPitchInput(LookVector.Y);
}
에러 : WS는 좌우로, AD는 앞뒤로 이동되는 결과 초래
- IA_BasicMove에서 Modifier를 추가해주도록 합니다.