ABCharacter
* 아래의 책의 내용을 정리한 글입니다! *
이번장은 폰클래스가 아닌 언리얼에서 미리 캐릭터에 대해서 만들어놓은 캐릭터클래스를
이용해 캐릭터를 만드는 내용입니다!
먼저 c++ 캐릭터 클래스를 하나 만들어주고
ABCharacter.h 파일에 들어가보면
UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{
...
위처럼 ACharacter을 상속받는 것을 볼수있습니다!
저 부분을 더블클릭후 F12 를 누르면 상속받은 헤더파일로 이동하게 되는데 여기서
이 파일또한 APawn 을 상속받는 다는것을 알수있습니다!
class ENGINE_API ACharacter : public APawn
{
GENERATED_BODY()
이 부분을 통해 캐릭터 클래스는 폰 클래스를 상속받아 확장시킨 클래스란 것을 알수있습니다!
그렇기에 이동부분은 앞선 5장의 코드와 다를게 없습니다! (복붙!)
이제 캐릭터 파일들을 수정하러 가봅시다!
이동은 되니 상하 카메라 이동을 구현해봅시다.
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;
}
}
코드를 모두 작성하면
모드가 잘 변경됨을 볼수있습니다!
여기까지가 끝!
틀린점이 있다면 댓 달아주세요!
'언리얼 최고 > 언리얼 c++' 카테고리의 다른 글
이득우의 언리얼 C++ 정리 - 8 (애니메이션 시스템 활용) (1) | 2022.08.30 |
---|---|
이득우의 언리얼 C++ 정리 - 7 (애니메이션 시스템의 설계) (0) | 2022.08.20 |
이득우의 언리얼 C++ 정리 - 5 (폰의 제작과 조작) (0) | 2022.08.19 |
이득우의 언리얼 C++ 정리 - 4 (게임플레이 프레임워크) (0) | 2022.08.17 |
언리얼 C++ 액터 삭제에 대해서! (0) | 2022.08.17 |
댓글