본문 바로가기
언리얼 최고/언리얼 c++

이득우의 언리얼 C++ 정리 - 6 (캐릭터의 제작과 컨트롤)

by Lee_story_.. 2022. 8. 20.
728x90

ABCharacter

*  아래의 책의 내용을 정리한 글입니다!  *

 

이번장은 폰클래스가 아닌 언리얼에서 미리 캐릭터에 대해서 만들어놓은 캐릭터클래스를

이용해 캐릭터를 만드는 내용입니다!

 

 

먼저 c++ 캐릭터 클래스를 하나 만들어주고 

ABCharacter.h 파일에 들어가보면

UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{
 ...

 

위처럼 ACharacter을 상속받는 것을 볼수있습니다! 

저 부분을 더블클릭후  F12 를 누르면 상속받은 헤더파일로 이동하게 되는데 여기서

 

이 파일또한 APawn 을 상속받는 다는것을 알수있습니다!

class ENGINE_API ACharacter : public APawn
{
	GENERATED_BODY()

 

이 부분을 통해 캐릭터 클래스폰 클래스를 상속받아 확장시킨 클래스란 것을 알수있습니다!

그렇기에 이동부분은 앞선 5장의 코드와 다를게 없습니다! (복붙!)

 

 

이득우의 언리얼 C++ 정리 - 5 (폰의 제작과 조작)

* 아래의 책의 내용을 정리한 글입니다! * 이번장에서는 폰을 조작하는 방법에 대한 내용이였습니다. 그럼 시작! 폰에도 기본적인 구성요소가 있습니다! - 먼저 그 요소들에 대해서 정리하면   

ljhyunstory.tistory.com

 

이제 캐릭터 파일들을 수정하러 가봅시다!

 

 

이동은 되니 상하 카메라 이동을 구현해봅시다.

 

ABCharacter.h에 추가

//~

private:
	void UpDown(float NewAxisValue);
	void LeftRight(float NewAxisValue);
	
	void LookUp(float NewAxisValue);
	void Turn(float NewAxisValue);

	void ViewChange();

//~

 

 

 

ABCharacter.cpp 에 추가

//~
PlayerInputComponent->BindAxis(TEXT("LookUp"), this, &AABCharacter::LookUp);
PlayerInputComponent->BindAxis(TEXT("Turn"), this, &AABCharacter::Turn);


//~


void AABCharacter::LookUp(float NewAxisValue)
{
	AddControllerPitchInput(NewAxisValue);
}

void AABCharacter::Turn(float NewAxisValue)
{
	AddControllerYawInput(NewAxisValue);
}

끝!

 

 

 

이번에는 카메라 모드변경을 하는것을 해보도록하겠습니다!

 

 

 

책에서는 디아블로식카메라와 GTA식 카메라 모드를 만들어서 관리하네요

 

디아블로식카메라

  • 캐릭터의 이동 : 상하좌우 키를 조합해 캐릭터가 이동할 방향을 결정
  • 캐릭터의 회전 : 캐릭터는 입력한 방향으로 회전
  • 카메라 지지대 길이 : 800cm
  • 카메라 회전 : 카메라의 회전 없이 항상 고정 시선으로 45도로 내려다봄
  • 카메라 줌 : 없음. 카메라와 캐릭터 사이에 장애물이 있는 경우 외곽선으로 처리

 

 

GTA식 카메라

  • 캐릭터의 이동 : 현재 보는 시점을 기준으로 상하, 좌우 방향으로 마네킹이 이동하고 카메라는 회전하지 않음
  • 캐릭터의 회전 : 캐릭터가 이동하는 방향으로 마네킹이 회전함
  • 카메라 지지대 길이 : 450cm
  • 카메라 회전 : 마우스 상하좌우 이동에 따라 카메라 지지대가 상하좌우로 회전
  • 카메라 줌 : 카메라 시선과 캐릭터 사이에 장애물이 감지되면 캐릭터가 보이도록 카메라를 장애물 앞으로 줌인

 

이렇게 봐서는..... 일단 만들어 보죠!

 

 

 

 

ABCharacter.h에 모드부터 추가

protected:
   enum class EControlMode {
		GTA,
		DIABLO
	};

	void SetControlMode(EControlMode NewControlMode);
	EControlMode CurrentControlMode = EControlMode::GTA;
	FVector DirectionToMove = FVector::ZeroVector;

	float ArmLengthTo = 0.0f;
	FRotator ArmRotationTo = FRotator::ZeroRotator;
	float ArmLengthSpeed = 0.0f;
	float ArmRotationSpeed = 0.0f;
    
    
 private:
    void ViewChange();

 

그다음 프로젝트세팅 >> 입력 >> 액션매핑에 ViewChange 추가 Shift + V 설정!

 

 

 

ABCharacter.cpp 파일 작성.... 좀 많네요....

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


#include "ABCharacter.h"

// 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;

	//Camera 생성/ 설정
	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.f, 0.0f));
	SpringArm->TargetArmLength = 400.0f;
	SpringArm->SetRelativeRotation(FRotator(-15.0f, 0.0f, 0.0f));

	//캐릭터 메시와 애니메이션!--------------------------------------------------------------------------
	static ConstructorHelpers::FObjectFinder<USkeletalMesh> SK_CARDBOARD(TEXT("/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Golden.SK_CharM_Golden"));
	if (SK_CARDBOARD.Succeeded())
	{
		GetMesh()->SetSkeletalMesh(SK_CARDBOARD.Object);
	}

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

	static ConstructorHelpers::FClassFinder<UAnimInstance> WARRIOR_ANIM(TEXT("/Game/InfinityBladeWarriors/Animation/WarriotAnimBluePrint.WarriotAnimBluePrint_C"));
	if (WARRIOR_ANIM.Succeeded())
	{
		GetMesh()->SetAnimInstanceClass(WARRIOR_ANIM.Class);
	}
	//---------------------------------------------------------------------------------------------------------------
	

	// 기본모드 :  DIABLO 
	SetControlMode(EControlMode::DIABLO);

	//카메라 전환 속도설정!
	ArmLengthSpeed = 3.0f;
	ArmRotationSpeed = 10.0f;
}

// Called when the game starts or when spawned
void AABCharacter::BeginPlay()
{
	Super::BeginPlay();

}

// Called every frame
void AABCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// 모드전환시 서서히 변경되도록하는 부분
	SpringArm->TargetArmLength = FMath::FInterpTo(SpringArm->TargetArmLength, ArmLengthTo, DeltaTime, ArmLengthSpeed);

	switch (CurrentControlMode)//모드확인후 변경
	{
	case EControlMode::DIABLO:
		SpringArm->SetRelativeRotation(FMath::RInterpTo(SpringArm->GetRelativeRotation(), ArmRotationTo, DeltaTime, ArmRotationSpeed));
		break;
	}

	switch (CurrentControlMode)
	{
	case EControlMode::DIABLO:
		if (DirectionToMove.SizeSquared() > 0.0f)
		{
			GetController()->SetControlRotation(FRotationMatrix::MakeFromX(DirectionToMove).Rotator());
			AddMovementInput(DirectionToMove);
		}
		break;
	}
}

// Called to bind functionality to input
void AABCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	// 모드변경 버튼!
	PlayerInputComponent->BindAction(TEXT("ViewChange"), EInputEvent::IE_Pressed, this, &AABCharacter::ViewChange);

	PlayerInputComponent->BindAxis(TEXT("UpDown"), this, &AABCharacter::UpDown);
	PlayerInputComponent->BindAxis(TEXT("LeftRight"), this, &AABCharacter::LeftRight);
	PlayerInputComponent->BindAxis(TEXT("LookUp"), this, &AABCharacter::LookUp);
	PlayerInputComponent->BindAxis(TEXT("Turn"), this, &AABCharacter::Turn);
}

void AABCharacter::UpDown(float NewAxisValue)
{

	switch (CurrentControlMode)
	{
	case EControlMode::GTA:
		AddMovementInput(FRotationMatrix(FRotator(0.0f, GetControlRotation().Yaw, 0.0f)).GetUnitAxis(EAxis::X), NewAxisValue);
		break;
	case EControlMode::DIABLO:
		DirectionToMove.X = NewAxisValue;
		break;
	}
}

void AABCharacter::LeftRight(float NewAxisValue)
{
	switch (CurrentControlMode)
	{
	case EControlMode::GTA:
		AddMovementInput(FRotationMatrix(FRotator(0.0f, GetControlRotation().Yaw, 0.0f)).GetUnitAxis(EAxis::Y), NewAxisValue);
		break;
	case EControlMode::DIABLO:
		DirectionToMove.Y = NewAxisValue;
		break;
	}
}

void AABCharacter::LookUp(float NewAxisValue)
{
	switch (CurrentControlMode)
	{
	case EControlMode::GTA:
		AddControllerPitchInput(NewAxisValue);
		break;
	}

}

void AABCharacter::Turn(float NewAxisValue)
{
	switch (CurrentControlMode)
	{
	case EControlMode::GTA:
		AddControllerYawInput(NewAxisValue);
		break;
	}
}

void AABCharacter::SetControlMode(EControlMode NewControlMode)
{
	CurrentControlMode = NewControlMode;

	switch (CurrentControlMode)
	{
	case EControlMode::GTA://마우스 입력 받음!

		ArmLengthTo = 450.0f;

		SpringArm->bUsePawnControlRotation = true;
		SpringArm->bInheritPitch = true;
		SpringArm->bInheritRoll = true;
		SpringArm->bInheritYaw = true;

		// 이부분은 카메라가 다른 액터와 충돌할지를 보는부분으로 충돌되면 카메라가 줌되면서 캐릭터와 가까워짐!
		SpringArm->bDoCollisionTest = true;

		// 4.26 부터 bOrientRotationToMovement 에 의해 대체됨.
		bUseControllerRotationYaw = false;

		// 캐릭터가 움직이는 방향으로 캐릭터를 자동으로 회전시켜 준는부분
		GetCharacterMovement()->bOrientRotationToMovement = true;

		//캐릭터 이동방향을 정확히 정해주는 부분!
		GetCharacterMovement()->bUseControllerDesiredRotation = false;

		// 회전을 부드럽게
		GetCharacterMovement()->RotationRate = FRotator(0.0f, 720.0f, 0.0f);
		break;

	
	case EControlMode::DIABLO:// 이동키만 받음;
	
		ArmLengthTo = 800.0f;
		ArmRotationTo = FRotator(-45.0f, 0.0f, 0.0f);
		SpringArm->bUsePawnControlRotation = false;
		SpringArm->bInheritPitch = false;
		SpringArm->bInheritRoll = false;
		SpringArm->bInheritYaw = false;
		SpringArm->bDoCollisionTest = false;

		bUseControllerRotationYaw = false;
		GetCharacterMovement()->bOrientRotationToMovement = false;
		GetCharacterMovement()->bUseControllerDesiredRotation = true;
		GetCharacterMovement()->RotationRate = FRotator(0.0f, 720.0f, 0.0f);
		break;
	}
}

void AABCharacter::ViewChange()
{
	switch (CurrentControlMode)
	{
	case EControlMode::GTA:
		GetController()->SetControlRotation(GetActorRotation());
		SetControlMode(EControlMode::DIABLO);
		break;
	case EControlMode::DIABLO:
		GetController()->SetControlRotation(SpringArm->GetRelativeRotation());
		SetControlMode(EControlMode::GTA);
		break;
	}
}

 

코드를 모두 작성하면

 

모드가 잘 변경됨을 볼수있습니다!

 

 

 

여기까지가 끝!

 

 

 

 

 

틀린점이 있다면 댓 달아주세요!

댓글