반응형
- 스켈레탈 메시를 코드로 불러온다.
ConstructorHelpers::FObjectFinder<USkeletalMesh> TempMesh(TEXT("SkeletalMesh'/Game/Mannequin/Character/Mesh/SK_Mannequin_Female.SK_Mannequin_Female'"));
- 스켈레탈 메시의 위치와 회전값을 설정한다.
// 1. 스켈레탈 메시 데이터를 불러오기
ConstructorHelpers::FObjectFinder<USkeletalMesh> TempMesh(TEXT("SkeletalMesh'/Game/Mannequin/Character/Mesh/SK_Mannequin_Female.SK_Mannequin_Female'"));
if (TempMesh.Succeeded())
{
GetMesh()->SetSkeletalMesh(TempMesh.Object);
// 2. Mesh 컴포넌트의 위치와 회전값을 설정하기
GetMesh()->SetRelativeLocationAndRotation(FVector(0, 0, -90), FRotator(0, -90, 0));
}
- 3인칭 카메라 암 붙히기
- TPSPlayer.h 파일 →
public:
UPROPERTY(VisibleAnywhere, Category = Camera)
class USpringArmComponent* springArmComp;
- USpringArmComponent 는 이 컴포넌트로 등록된 자식 컴포넌트를 자신과의 지정된 거리 안에 유지되도록 처리하는 컴포넌트이다. 또한, 타깃과의 사이에 장애물이 있을 경우 장애물 앞으로 이동시커주는 탄력적인 움직임을 보여준다.
- springarmComponent 생성과 설정
#include <GameFramework/SpringArmComponent.h>
springArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
springArmComp->SetupAttachment(RootComponent);
springArmComp->SetRelativeLocation(FVector(0, 70, 90));
springArmComp->TargetArmLength = 400;
- 카메라 달기
- 헤더파일 →
UPROPERTY(VisibleAnywhere, Category = Camera)
class UCameraComponent* tpsCamComp;
- CPP
#include <Camera/CameraComponent.h>
// 카메라 컴포넌트 붙이기
tpsCamComp = CreateDefaultSubobject<UCameraComponent>(TEXT("TpsCamComp"));
tpsCamComp->SetupAttachment(springArmComp);
- 플레이어 회전 시키기
- 스프링암 컴포넌트에서의 Camera Settings 카테고리에서 Use Pawn Control Rotation 체크박스가 있다. 이 값은 폰에 회전 입력이 들어오면 스프링암 컴포넌트를 회전시킬지의 여부를 나타낸다. 체크하여 활성화 한다.
springArmComp->bUsePawnControlRotation = true;
tpsCamComp->bUsePawnControlRotation = false;
bUseControllerRotationYaw = true;
- 상하 좌우 카메라 회전
// Called to bind functionality to input
void ATPSPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis(TEXT("LookUP"), this, &ATPSPlayer::LookUp);
PlayerInputComponent->BindAxis(TEXT("Turn"), this, &ATPSPlayer::Turn);
}
void ATPSPlayer::Turn(float value)
{
AddControllerYawInput(value);
}
void ATPSPlayer::LookUp(float value)
{
AddControllerPitchInput(value);
}
- 플레이어 이동 제어
- 헤더파일→
// 이동 속도
UPROPERTY(EditAnywhere, Category = PlayerSetting)
float walkSpeed = 600;
// 이동 방향
FVector direction;
// 좌우 이동 입력 이벤트 처리 함수
void InputHorizontal(float value);
// 상하 이동 입력 이벤트 처리 함수
void InputVertical(float value);
- C++ 파일→
// Fill out your copyright notice in the Description page of Project Settings.
#include "TPSPlayer.h"
#include <GameFramework/SpringArmComponent.h>
#include <Camera/CameraComponent.h>
// Sets default values
ATPSPlayer::ATPSPlayer()
{
// 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;
// 1. 스켈레탈 메시 데이터를 불러오기
ConstructorHelpers::FObjectFinder<USkeletalMesh> TempMesh(TEXT("SkeletalMesh'/Game/Mannequin/Character/Mesh/SK_Mannequin_Female.SK_Mannequin_Female'"));
if (TempMesh.Succeeded())
{
GetMesh()->SetSkeletalMesh(TempMesh.Object);
// 2. Mesh 컴포넌트의 위치와 회전값을 설정하기
GetMesh()->SetRelativeLocationAndRotation(FVector(0, 0, -90), FRotator(0, -90, 0));
}
springArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
springArmComp->SetupAttachment(RootComponent);
springArmComp-> SetRelativeLocation(FVector(0, 70, 90));
springArmComp->TargetArmLength = 400;
springArmComp->bUsePawnControlRotation = true;
// 카메라 컴포넌트 붙이기
tpsCamComp = CreateDefaultSubobject<UCameraComponent>(TEXT("TpsCamComp"));
tpsCamComp->SetupAttachment(springArmComp);
tpsCamComp->bUsePawnControlRotation = false;
bUseControllerRotationYaw = true;
}
// Called when the game starts or when spawned
void ATPSPlayer::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ATPSPlayer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 플레이어 이동 처리
// 등속 운동
// P(결과 위치) = PO(현재 위치)+ v(속도) x t(시간)
FVector PO = GetActorLocation();
FVector vt = direction * walkSpeed * DeltaTime;
FVector P = PO + vt;
SetActorLocation(P);
direction = FVector::ZeroVector;
}
// Called to bind functionality to input
void ATPSPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis(TEXT("LookUP"), this, &ATPSPlayer::LookUp);
PlayerInputComponent->BindAxis(TEXT("Turn"), this, &ATPSPlayer::Turn);
//좌우 입력 이벤트 처리 함수 바인딩
PlayerInputComponent->BindAxis(TEXT("Horizontal"), this, &ATPSPlayer::InputHorizontal);
//상하 입력 이벤트 처리 함수 바인딩
PlayerInputComponent->BindAxis(TEXT("Vertical"), this, &ATPSPlayer::InputVertical);
}
void ATPSPlayer::Turn(float value)
{
AddControllerYawInput(value);
}
void ATPSPlayer::LookUp(float value)
{
AddControllerPitchInput(value);
}
void ATPSPlayer::InputHorizontal(float value)
{
direction.Y = value;
}
void ATPSPlayer::InputVertical(float value)
{
direction.X = value;
}
- 위에 코드는 플레이어가 바라보는 방향과는 상관 없이 절대적인 좌표값을 이용하여 움직이기 때문에 원하는 바 처럼 이동하지 않는다. 카메라에 회전 값에 따라 좌우 이동이 되게 하려면 회전값을 받아오는 코드를 짜야 한다.
void ATPSPlayer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 플레이어 이동 처리
// 등속 운동
// P(결과 위치) = PO(현재 위치)+ v(속도) x t(시간)
direction = FTransform(GetControlRotation()).TransformVector(direction);
FVector PO = GetActorLocation();
FVector vt = direction * walkSpeed * DeltaTime;
FVector P = PO + vt;
SetActorLocation(P);
direction = FVector::ZeroVector;
}
- 다음은 Character 클래스에서 제공하는 함수를 사용한 코드입니다.
void ATPSPlayer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 플레이어 이동 처리
// 등속 운동
// P(결과 위치) = PO(현재 위치)+ v(속도) x t(시간)
direction = FTransform(GetControlRotation()).TransformVector(direction);
/*FVector PO = GetActorLocation();
FVector vt = direction * walkSpeed * DeltaTime;
FVector P = PO + vt;
SetActorLocation(P);*/
AddMovementInput(direction);
direction = FVector::ZeroVector;
}
- 점프 구현하기
- Input 창에 binding action에서 Jump 설정하기
- Tip
- 스프링암 컴포넌트의 Lag 속성이 있다. 이 속성은 3인칭 모드의 카메라가 타깃을 따라 이동 또는 회전할 때 지연되어 부드럽게 따라갈 수 있도록 처리한다. TPS 게임에서는 사용하기 애매하지만 다른 3인칭 콘테츠에서는 사용하면 멋진 카메라 움직임을 표현할 수 있다.
느낀점
- 동적 할당이 상당히 편리하다는 것을 깨달았다. 왜냐하면 블루프린트가 생각보다 너무 자주 오류가 나서 변경한 점이 적용이 안되는 경우가 많은데 이것을 고치는 데에 두 가지 방법이 있다.
- 언리얼 엔진을 껐다가 키는 방법.
- 블루 프린트를 삭제 했다가 다시 생성하는 방법
- 확실한 방법은 2 번째 방법으로 블루 프린트를 삭제 했다가 다시 생성하는 방법인데 만약 동적으로 할당하지 않고 블루 프린트에서 일일이 손으로 수정을 해줘야 하는 작업이 있다면 그 작업들을 다시 다 해줘야 한다. 상당히 복잡해 진다. 심지어 포인터 같은 경우 null 포인터를 참조하여 엔진이 꺼지는 경우도 생겨서 코드를 짤 때 항상 null 체크를 하는 것을 습관화 해야 겠다.
반응형
'Unreal' 카테고리의 다른 글
[Unreal Engine C++] RPG Camera 구현과 캐릭터 애니메이션 (0) | 2023.03.26 |
---|---|
언리얼 Mobility 특성 (0) | 2023.03.05 |
언리얼 - 블루프린트 사용 (출력하기, 조건문) (0) | 2023.03.05 |
[Unreal 4] 오브젝트 충돌 감지 - C++ (0) | 2023.01.15 |
[Unreal] 캐릭터 이동 및 마우스로 화면 전환 (1) - C++ (Character Class) (0) | 2023.01.04 |