다양한 기록

[UE Game Framework] #3 Character Control Setting 본문

언리얼 엔진/Unreal Game Framework

[UE Game Framework] #3 Character Control Setting

라구넹 2025. 1. 3. 22:28

캐릭터 컨트롤 요소

- 일반적으로 컨트롤러, 카메라, 스프링암, 캐릭터 무브먼트 다섯가지 요소

- 컨트롤러: 입력자의 의지(목표 지점)을 지정시 사용, ControlRotation 속성

- : 폰의 트랜스폼을 지정

- 카메라: 화면 구도를 설정하기 위해 사용, 주로 1인칭 시점에서 사용

- 스프링암: 화면 구도를 설정하기 위해 사용, 주로 3인칭 시점에서 사용

- 캐릭터 무브먼트: 캐릭터의 이동과 회전을 조정하는 용도로 사용

 

Desired Rotation : 내가 앞으로 회전해야 할 최종 목표, 의지를 나타내는 회전값

Rotation : 현재 회전된 상태

Desired Rotation으로 값을 덮어씌우고 필요 시 Rotation rate로 지정된 각속도로 회전

 

폰의 이동 함수

Look 함수 : 마우스 입력으로부터 컨트롤러의 컨트롤 회전을 설정

Move 함수 : 컨트롤러의 컨트롤 회전으로부터 Yaw 값을 참고해 이동 방향을 설정

콘솔 커맨드 창(단축키 ~)으로부터 Control Rotation 값을 확인 가능

Control Rotation으로 이동과 시점을 조절

void AABCharacterPlayer::Look(const FInputActionValue& Value)
{
	FVector2D LookAxisVector = Value.Get<FVector2D>();

	AddControllerYawInput(LookAxisVector.X);
	AddControllerPitchInput(LookAxisVector.Y);
}

인풋값을 받아 AddControllerYawInput랑 AddControllerPitchInput을 실행함

플레이어 컨트롤러의 포인트를 가져와 AddYawInput 실행

로테이션 인풋 속성의 Yaw 회전 값에 집어넣은 입력의 크기를 추가해줌 

void APlayerController::UpdateRotation( float DeltaTime )
{
	// Calculate Delta to be applied on ViewRotation
	FRotator DeltaRot(RotationInput);

	FRotator ViewRotation = GetControlRotation();

	if (PlayerCameraManager)
	{
		PlayerCameraManager->ProcessViewRotation(DeltaTime, ViewRotation, DeltaRot);
	}

	AActor* ViewTarget = GetViewTarget();
	if (!PlayerCameraManager || !ViewTarget || !ViewTarget->HasActiveCameraComponent() || ViewTarget->HasActivePawnControlCameraComponent())
	{
		if (IsLocalPlayerController() && GEngine->XRSystem.IsValid() && GetWorld() != nullptr && GEngine->XRSystem->IsHeadTrackingAllowedForWorld(*GetWorld()))
		{
			auto XRCamera = GEngine->XRSystem->GetXRCamera();
			if (XRCamera.IsValid())
			{
				XRCamera->ApplyHMDRotation(this, ViewRotation);
			}
		}
	}

	SetControlRotation(ViewRotation);

	APawn* const P = GetPawnOrSpectator();
	if (P)
	{
		P->FaceRotation(ViewRotation, DeltaTime);
	}
}

로테이션 인풋은 DeltaRot 구축에 사용되고

ViewRotation이라는 값에 델타 로테이션이 활용됨 

해당값은 SetControlRotation 함수에 넣어서 최종 Control Rotation 속성을 지정한 새로운 로테이션으로 덮어씀

 

void AABCharacterPlayer::Move(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();

	const FRotator Rotation = Controller->GetControlRotation();
	const FRotator YawRotation(0, Rotation.Yaw, 0);

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

	AddMovementInput(ForwardDirection, MovementVector.X);
	AddMovementInput(RightDirection, MovementVector.Y);
}

무브 함수는 위에서 업데이트된 컨트롤 로테이션 값을 가져오고

해당 로테이션을 기점으로 전진 방향과 오른쪽 방향을 얻어오고, 캐릭터를 이동시킴

 

~ 누르고 위 커맨드 입력

 

Look 함수의 인풋으로 저게 변함

* 좌우로 움직이면 Yaw가, 위아래는 Pitch가 바뀜

저상태에서 움직이면 ControlRotation의 값을 가져와서 이동

 

폰의 컨트롤 옵션

- Use Control Rotation (Yaw / Roll / Pitch)

- 컨트롤러에 지정된 Control Rotation 값에 폰의 Rotation을 맞출 것인가?

- 옵션 키면 폰의 회전은 컨트롤러의 Control Rotation과 동기화

 

스프링암의 컨트롤 옵션

스프링암의 컨트롤 옵션

- Use Pawn Control Rotation : 폰의 컨트롤 회전(Controller의 Control Rotation)을 사용할 것인가?

- Inherit (Yaw / Pitch / Roll) : 부모 컴포넌트(주로 루트컴포넌트)의 회전을 그대로 따를 것인가?

- Do Collision Test : 스프링암 중간에 장애물이 있으면 앞으로 당길 것인가? (Camera라는 트레이스 채널 사용)

체크되어 있어서 마우스 움직이니 스프링암이 같이 회전

- 3인칭

 

카메라 컨트롤 옵션

- Use Pawn Control Rotation

- 스프링암에 달려있다면 스프링암의 회전과 함께 고려

- 1인칭 카메라 회전 

 

캐릭터 무브먼트의 이동 옵션

- Movement Mode : None, Walking, Falling ..

- 땅 위에 있으면 Walking

- 땅 위에 없으면 Failling

- 이동 기능을 끄고 싶으면 None 모드

- 이동 모드에서의 이동 수치 : MaxWalkSpeed

- 폴링 모드에서의 점프 수치 : JumpZVelocity

 

캐릭터 무브먼트의 회전 옵션

- Rotation Rate : 회전 속도의 지정

- Use Controller Desired Rotation : 컨트롤 로테이션을 목표 회전으로 잡고 지정한 속도로 돌리기

- Orient Rotation To Movement : 캐릭터 이동 방향에 회전을 일치시키기

- 폰의 회전 옵션과 충돌이 나지 않도록 주의


데이터 애셋

- UDataAsset 을 상속받은 언리얼 오브젝트 클래스

- 에디터에서 애셋 형태로 편리하게 데이터 관리 가능

- 캐릭터 컨트롤에 관련된 주요 옵션을 모아 애셋으로 관리

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "ABCharacterControlData.generated.h"

/**
 * 
 */
UCLASS()
class ARENABATTLE_API UABCharacterControlData : public UPrimaryDataAsset
{
	GENERATED_BODY()
	
public:
	UABCharacterControlData();

	UPROPERTY(EditAnywhere, Category = Pawn)
	uint32 bUseControllerRotationYaw : 1;

	UPROPERTY(EditAnywhere, Category = CharacterMovement)
	uint32 bOrientRotationToMovement : 1;

	UPROPERTY(EditAnywhere, Category = CharacterMovement)
	uint32 bUseControllerDesiredRotation : 1;

	UPROPERTY(EditAnywhere, Category = CharacterMovement)
	FRotator RotationRate;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
	TObjectPtr<class UInputMappingContext> InputMappingContext;

	UPROPERTY(EditAnywhere, Category = SpringArm)
	float TargetArmLength;

	UPROPERTY(EditAnywhere, Category = SpringArm)
	FRotator RelativeRotation;

	UPROPERTY(EditAnywhere, Category = SpringArm)
	uint32 bUsePawnControlRotation : 1;

	UPROPERTY(EditAnywhere, Category = SpringArm)
	uint32 bInheritPitch : 1;

	UPROPERTY(EditAnywhere, Category = SpringArm)
	uint32 bInheritYaw : 1;

	UPROPERTY(EditAnywhere, Category = SpringArm)
	uint32 bInheritRoll : 1;

	UPROPERTY(EditAnywhere, Category = SpringArm)
	uint32 bDoCollisionTest : 1;
};

UPROPERTY(EditAnywhere, Category = Pawn)
uint32 bUseControllerRotationYaw : 1;

- 캐릭터는 보통 Contoller Rotation은 Yaw만 씀

 

 

UPROPERTY(EditAnywhere, Category = CharacterMovement)
uint32 bOrientRotationToMovement : 1;
UPROPERTY(EditAnywhere, Category = CharacterMovement)
uint32 bUseControllerDesiredRotation : 1;
UPROPERTY(EditAnywhere, Category = CharacterMovement)
FRotator RotationRate;

- 무브먼트에서 사용하는 변수

 

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
TObjectPtr<class UInputMappingContext> InputMappingContext;

- 입력 매핑 컨텍스트를 담을 멤버변수 선언

 

UPROPERTY(EditAnywhere, Category = SpringArm)
float TargetArmLength;
UPROPERTY(EditAnywhere, Category = SpringArm)
FRotator RelativeRotation;
UPROPERTY(EditAnywhere, Category = SpringArm)
uint32 bUsePawnControlRotation : 1;
UPROPERTY(EditAnywhere, Category = SpringArm)
uint32 bInheritPitch : 1;
UPROPERTY(EditAnywhere, Category = SpringArm)
uint32 bInheritYaw : 1;
UPROPERTY(EditAnywhere, Category = SpringArm)
uint32 bInheritRoll : 1;
UPROPERTY(EditAnywhere, Category = SpringArm)
uint32 bDoCollisionTest : 1;

- 스프링암 관련

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "Character/ABCharacterControlData.h"

UABCharacterControlData::UABCharacterControlData()
{
	TargetArmLength = 400.0f;
}

타겟 암 렝스만 기본값을 줌

 

이제 데이터 애셋 만들 수 있음

 

데이터 애셋의 관리

두가지의 컨트롤 모드를 제공

- 현재 구현된 컨트롤 모드 : 3인칭 숄더뷰

- 추가로 구현할 컨트롤 모드 : 3인칭 쿼터뷰

입력키 V를 통해 컨트롤 설정을 변경

ENUM을 통해 두 개의 컨트롤 데이터 관리

-> 이를 위해 컨트롤 관리자 자료구조를 만들 것

 

데이터 애셋의 구성과 적용

각 섹션별로 데이터를 저장

- Pawn 카테고리

- CharacterMovement 카테고리

- 인풋 카테고리

- 스프링암 카테고리

Pawn과 캐릭터 무브먼트 데이터는 CharacterBase에서 설정

입력과 스프링암 데이터는 CharacterPlayer에서 설정

 

뷰의 변환

컨트롤을 변경할 때 서로 다른 입력 매핑 컨택스트를 지정

숄더뷰: ShoulderMove와 ShoulderLook 사용

쿼터뷰: QuaterMove만 사용

입력 액션을 사용해 변경

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "ABCharacterBase.generated.h"

UENUM()
enum class ECharacterControlType : uint8
{
	Shoulder,
	Quater
};

UCLASS()
class ARENABATTLE_API AABCharacterBase : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AABCharacterBase();
	virtual void SetCharacterControlData(const class UABCharacterControlData* CharacterControlData);

	UPROPERTY(EditAnywhere, Category = CharacterControl, Meta = (AllowPrivateAccess = "true"))
	TMap<ECharacterControlType, class UABCharacterControlData*> CharacterControlManager;
};

캐릭터 베이스 헤더

// Fill out your copyright notice in the Description page of Project Settings.


#include "Character/ABCharacterBase.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "ABCharacterControlData.h"

// Sets default values
AABCharacterBase::AABCharacterBase()
{
	// Pawn rotation
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Capsule
	GetCapsuleComponent()->InitCapsuleSize(42.0f, 96.0f);
	GetCapsuleComponent()->SetCollisionProfileName(TEXT("Pawn"));

	// Movement
	GetCharacterMovement()->bOrientRotationToMovement = true;
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f);
	GetCharacterMovement()->JumpZVelocity = 700.0f;
	GetCharacterMovement()->AirControl = 0.35f;
	GetCharacterMovement()->MaxWalkSpeed = 500.0f;
	GetCharacterMovement()->MinAnalogWalkSpeed = 20.0f;
	GetCharacterMovement()->BrakingDecelerationWalking = 2000.0f;

	// Mesh
	GetMesh()->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, -100.0f), FRotator(0.0f, -90.0f, 0.0f));
	GetMesh()->SetAnimationMode(EAnimationMode::AnimationBlueprint);
	GetMesh()->SetCollisionProfileName(TEXT("CharacterMesh"));

	static ConstructorHelpers::FObjectFinder<USkeletalMesh> CharacterMeshRef(TEXT("/Script/Engine.SkeletalMesh'/Game/Characters/Mannequins/Meshes/SKM_Quinn_Simple.SKM_Quinn_Simple'"));
	if (CharacterMeshRef.Object)
	{
		GetMesh()->SetSkeletalMesh(CharacterMeshRef.Object);
	}

	static ConstructorHelpers::FClassFinder<UAnimInstance> AnimInstanceClassRef(TEXT("/Game/Characters/Mannequins/Animations/ABP_Quinn.ABP_Quinn_C"));
	if (AnimInstanceClassRef.Class)
	{
		GetMesh()->SetAnimInstanceClass(AnimInstanceClassRef.Class);
	}

	static ConstructorHelpers::FObjectFinder<UABCharacterControlData> ShoulderObjectRef(TEXT("/Script/ArenaBattle.ABCharacterControlData'/Game/ArenaBattle/CharcaterControl/ABC_Shoulder.ABC_Shoulder'"));
	if (ShoulderObjectRef.Object)
	{
		CharacterControlManager.Add(ECharacterControlType::Shoulder, ShoulderObjectRef.Object);
	}

	static ConstructorHelpers::FObjectFinder<UABCharacterControlData> QueterObjectRef(TEXT("/Script/ArenaBattle.ABCharacterControlData'/Game/ArenaBattle/CharcaterControl/ABC_Quater.ABC_Quater'"));
	if (QueterObjectRef.Object)
	{
		CharacterControlManager.Add(ECharacterControlType::Quater, QueterObjectRef.Object);
	}
}

void AABCharacterBase::SetCharacterControlData(const UABCharacterControlData* CharacterControlData)
{
	// Pawn
	bUseControllerRotationYaw = CharacterControlData->bUseControllerRotationYaw;

	// CharacterMovement
	GetCharacterMovement()->bOrientRotationToMovement = CharacterControlData->bOrientRotationToMovement;
	GetCharacterMovement()->bUseControllerDesiredRotation = CharacterControlData->bUseControllerDesiredRotation;
	GetCharacterMovement()->RotationRate = CharacterControlData->RotationRate;
}

캐릭터 베이스 구현 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Character/ABCharacterBase.h"
#include "InputActionValue.h"
#include "ABCharacterPlayer.generated.h"

/**
 * 
 */
UCLASS()
class ARENABATTLE_API AABCharacterPlayer : public AABCharacterBase
{
	GENERATED_BODY()
	
public:
	AABCharacterPlayer();

protected:
	virtual void BeginPlay() override;

public:
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

// Character Controll Section
protected:
	void ChangeCharacterControl();
	void SetCharacterControl(ECharacterControlType NewCharacterControlType);
	virtual void SetCharacterControlData(const class UABCharacterControlData* CharacterControlData);

// Camera Section
protected:
	// Meta 설정 .. Private로 설정된 객체들을 블루프린트에서 접근할 수 있도록 함 
	// 스프링 암 == 카메라 지지대
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class USpringArmComponent> CameraBoom;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UCameraComponent> FollowCamera;

// Input Section
protected:
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> JumpAction;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> ChangeControlAction;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> ShoulderMoveAction;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> ShoulderLookAction;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> QuaterMoveAction;

	void ShoulderMove(const FInputActionValue& Value);
	void ShoulderLook(const FInputActionValue& Value);

	void QuaterMove(const FInputActionValue& Value);

	ECharacterControlType CurrentCharacterControlType;
};

캐릭터 플레이어 헤더

// Fill out your copyright notice in the Description page of Project Settings.


#include "Character/ABCharacterPlayer.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "InputMappingContext.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "ABCharacterControlData.h"

AABCharacterPlayer::AABCharacterPlayer()
{
	// Camera
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 400.0f;
	CameraBoom->bUsePawnControlRotation = true;

	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
		// 소켓 지정자 사용하면 스프링 암 끝에 알아서 붙음 
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
	FollowCamera->bUsePawnControlRotation = false;

	// Input
	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionJumpRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ArenaBattle/Input/Actions/IA_Jump.IA_Jump'"));
	if (nullptr != InputActionJumpRef.Object)
	{
		JumpAction = InputActionJumpRef.Object;
	}

	static ConstructorHelpers::FObjectFinder<UInputAction> InputChangeActionControlRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ArenaBattle/Input/Actions/IA_ChangeControl.IA_ChangeControl'"));
	if (nullptr != InputChangeActionControlRef.Object)
	{
		ChangeControlAction = InputChangeActionControlRef.Object;
	}

	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionShoulderMoveRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ArenaBattle/Input/Actions/IA_ShoulderMove.IA_ShoulderMove'"));
	if (nullptr != InputActionShoulderMoveRef.Object)
	{
		ShoulderMoveAction = InputActionShoulderMoveRef.Object;
	}

	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionShoulderLookRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ArenaBattle/Input/Actions/IA_ShoulderLook.IA_ShoulderLook'"));
	if (nullptr != InputActionShoulderLookRef.Object)
	{
		ShoulderLookAction = InputActionShoulderLookRef.Object;
	}

	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionQuaterMoveRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ArenaBattle/Input/Actions/IA_QuaterMove.IA_QuaterMove'"));
	if (nullptr != InputActionQuaterMoveRef.Object)
	{
		QuaterMoveAction = InputActionQuaterMoveRef.Object;
	}

	CurrentCharacterControlType = ECharacterControlType::Quater;
}

void AABCharacterPlayer::BeginPlay()
{
	Super::BeginPlay();

	SetCharacterControl(CurrentCharacterControlType);
}

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

	// EnhancedInputComponent를 사용하지 않은 경우가 있을 수 있어 CastChecked
	UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);

	EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
	EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
	EnhancedInputComponent->BindAction(ChangeControlAction, ETriggerEvent::Triggered, this, &AABCharacterPlayer::ChangeCharacterControl);
	EnhancedInputComponent->BindAction(ShoulderMoveAction, ETriggerEvent::Triggered, this, &AABCharacterPlayer::ShoulderMove);
	EnhancedInputComponent->BindAction(ShoulderLookAction, ETriggerEvent::Triggered, this, &AABCharacterPlayer::ShoulderLook);
	EnhancedInputComponent->BindAction(QuaterMoveAction, ETriggerEvent::Triggered, this, &AABCharacterPlayer::QuaterMove);
}

void AABCharacterPlayer::ChangeCharacterControl()
{
	if (CurrentCharacterControlType == ECharacterControlType::Quater)
	{
		SetCharacterControl(ECharacterControlType::Shoulder);
	}
	else if (CurrentCharacterControlType == ECharacterControlType::Shoulder)
	{
		SetCharacterControl(ECharacterControlType::Quater);
	}
}

void AABCharacterPlayer::SetCharacterControl(ECharacterControlType NewCharacterControlType)
{
	UABCharacterControlData* NewCharacterControl = CharacterControlManager[NewCharacterControlType];
	check(NewCharacterControl);

	SetCharacterControlData(NewCharacterControl);

	APlayerController* PlayerController = CastChecked<APlayerController>(GetController());
	if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
	{
		Subsystem->ClearAllMappings();

		UInputMappingContext* NewMappingContext = NewCharacterControl->InputMappingContext;

		if (NewMappingContext)
		{
			Subsystem->AddMappingContext(NewMappingContext, 0);
		}
	}

	CurrentCharacterControlType = NewCharacterControlType;
}

void AABCharacterPlayer::SetCharacterControlData(const UABCharacterControlData* CharacterControlData)
{
	Super::SetCharacterControlData(CharacterControlData);

	CameraBoom->TargetArmLength = CharacterControlData->TargetArmLength;
	CameraBoom->SetRelativeRotation(CharacterControlData->RelativeRotation);
	CameraBoom->bUsePawnControlRotation = CharacterControlData->bUsePawnControlRotation;
	CameraBoom->bInheritPitch = CharacterControlData->bInheritPitch;
	CameraBoom->bInheritYaw = CharacterControlData->bInheritYaw;
	CameraBoom->bInheritRoll = CharacterControlData->bInheritRoll;
	CameraBoom->bDoCollisionTest = CharacterControlData->bDoCollisionTest;
}

void AABCharacterPlayer::ShoulderMove(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();

	const FRotator Rotation = Controller->GetControlRotation();
	const FRotator YawRotation(0, Rotation.Yaw, 0);

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

	AddMovementInput(ForwardDirection, MovementVector.X);
	AddMovementInput(RightDirection, MovementVector.Y);
}

void AABCharacterPlayer::ShoulderLook(const FInputActionValue& Value)
{
	FVector2D LookAxisVector = Value.Get<FVector2D>();

	AddControllerYawInput(LookAxisVector.X);
	AddControllerPitchInput(LookAxisVector.Y);
}

void AABCharacterPlayer::QuaterMove(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();

	float InputSizeSquared = MovementVector.SquaredLength();
	float MovementVectorSize = 1.0f;
	float MovementVectorSizeSquared = MovementVector.SquaredLength();
	if (MovementVectorSizeSquared > 1.0f)
	{
		MovementVector.Normalize();
		MovementVectorSizeSquared = 1.0f;
	}
	else
	{
		MovementVectorSize = FMath::Sqrt(MovementVectorSizeSquared);
	}

	FVector MoveDirection = FVector(MovementVector.X, MovementVector.Y, 0.0f);
	GetController()->SetControlRotation(FRotationMatrix::MakeFromX(MoveDirection).Rotator());
	AddMovementInput(MoveDirection, MovementVectorSize);
}

캐릭터 플레이어 구현

인풋 매핑 컨텍스트 -> 직접 받는 입력이랑, 각 입력이랑 어떤 액션이 반응하는지 설정

각 액션은 SetupPlayerInputComponent에서 함수와 연결됨

 

SetCharacterControlData에서 데이터 애셋에서 데이터 불러들임

(* Base에선 폰이랑 캐릭터 무브먼트만 설정, 아래에서 카메라랑 인풋 설정)

 

전환 잘 됨