Unreal

TPS Project

TIM_0529 2023. 3. 24. 00:46
반응형
  • 스켈레탈 메시를 코드로 불러온다.
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인칭 콘테츠에서는 사용하면 멋진 카메라 움직임을 표현할 수 있다.

총알 제작하기

총알 발사하기

느낀점

  1. 동적 할당이 상당히 편리하다는 것을 깨달았다. 왜냐하면 블루프린트가 생각보다 너무 자주 오류가 나서 변경한 점이 적용이 안되는 경우가 많은데 이것을 고치는 데에 두 가지 방법이 있다.
    1. 언리얼 엔진을 껐다가 키는 방법.
    2. 블루 프린트를 삭제 했다가 다시 생성하는 방법
    1 번째 방법은 간혹 ( 이번 작업 중에는 높은 확률로) 효과가 없었다.만약 동적으로 할당하는 방식에 단점을 하나 말하자면, 만약 동적으로 찾아서 할당하는 파일에 경로가 바뀌거나 이름이 바뀐다면 실행이 안된다는 것 정도 일 것 같다.
  2. 확실한 방법은 2 번째 방법으로 블루 프린트를 삭제 했다가 다시 생성하는 방법인데 만약 동적으로 할당하지 않고 블루 프린트에서 일일이 손으로 수정을 해줘야 하는 작업이 있다면 그 작업들을 다시 다 해줘야 한다. 상당히 복잡해 진다. 심지어 포인터 같은 경우 null 포인터를 참조하여 엔진이 꺼지는 경우도 생겨서 코드를 짤 때 항상 null 체크를 하는 것을 습관화 해야 겠다.
반응형