본문 바로가기

Unreal 공부

5일차 (Unreal Document 튜토리얼 따라하기 2)

따라 할 튜토리얼
https://docs.unrealengine.com/ko/Programming/Tutorials/PlayerInput/index.html

 

플레이어 입력 및 폰

Pawn 클래스를 확장하여 플레이어 입력에 반응시킵니다.

docs.unrealengine.com

플레이어 입력 및 폰

플레이어 입력 및 폰 튜토리얼에서는 플레이어의 입력에 따라 Pawn이 움직일 수 있게 만든다.

Pawn에 대한 간단한 설명
입력 매핑의 종류

입력 매핑은 "편집 - 프로젝트 세팅-엔진-입력"에서 해줄 수 있으며
바인딩이라는 항목에서 액션 매핑, 축 매핑 중 적절한 것에 키를 할당해주면 된다.

키 설정하는 법

// "Grow" 키를 누르거나 뗄 때 반응합니다
InputComponent->BindAction("Grow", IE_Pressed, this, &AMyPawn::StartGrowing);
InputComponent->BindAction("Grow", IE_Released, this, &AMyPawn::StopGrowing);

// "MoveX" 와 "MoveY" 두 이동 충의 값에 매 프레임 반응합니다
InputComponent->BindAxis("MoveX", this, &AMyPawn::Move_XAxis);
InputComponent->BindAxis("MoveY", this, &AMyPawn::Move_YAxis);

여기서 액션 매핑은 Grow이고 축 매핑은 MouseX와 MouseY인데
이것은 아까 프로젝트 세팅에서 해주었던 이름과 동일하게 해주어야 한다.

직접 해보기!

직접 해보기

이번 튜토리얼에서는 직접 해보기에 있는 것을 모두 해보기로 했다.

1. 일정 기간동안 누르고 있으면 속력이 상승되는 방향 컨트롤

디테일 창에서 설정해주는 TimeToSpeedUp 변수의 값이 속도 증가의 주기가 됨
예를 들어서, TimeToSpeedUp이 2이면 2초마다 한 번씩 Speed가 AmoutOfAddSpeed만큼 늘어남

Speed는 초기 속력을 의미하며 원래 튜토리얼에서는 100.0f로 사용했던 것을 따로 설정할 수 있게 만들었음

이동하는 키(W,A,S,D)를 누르고 있을 때는 일정 주기마다 정해진만큼 상승하지만
키에서 떼면 처음의 속도로 돌아오게 만들기 위해서 StartSpeed라는 변수를 만들어서 초기 Speed값을 저장하게 만듦

ElapsedTime은 이동하는 키를 몇초 간 누르고 있었는지를 저장하기 위해서 만들었음
TimeToSpeedUp보다 ElapsedTime이 크면 Speed를 증가시키고 ElapsedTime을 0으로 만듦

bPressing은 이동하는 키를 누르고 있는 상태인가 아닌가를 체크하는 bool값

2. 사용자가 축 매핑 을 누르기 시작한 직후 액션 매핑 을 누르면
오브젝트를 최대 크기로 즉시 확장시키는 특수 입력 시퀀스

if (bGrowing && !CurrentVelocity.IsZero() && !bPressing) 
{
	CurrentScale = MaxScale;
}

액션 매핑을 눌렀다는 것은 bGrowing이 True라는 것이고
축 매핑을 누르기 시작한 직후라는 것은 "Grow"를 처리한 후에 "MoveX", "MoveY"를 처리하기 때문에
아직 이 줄("Grow"를 처리하는 영역 안)에서는 bPressing이 false이고
축 매핑을 눌렀다면 이동을 했다는 것이고 그렇다면 CurrentVelocity가 0은 아닐 것이기 때문에
이러한 조건에서 MaxScale로 바꾸게 만들었음

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"

UCLASS()
class FIRSTPROJECT_API AMyPawn : public APawn
{
	GENERATED_BODY()

public:
	// Sets default values for this pawn's properties
	AMyPawn();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	// 입력 함수
	void Move_XAxis(float AxisValue);
	void Move_YAxis(float AxisValue);
	void StartGrowing();
	void StopGrowing();

private:
	UPROPERTY(EditAnywhere)
	USceneComponent* OurVisibleComponent;

	FVector CurrentVelocity;
	bool bGrowing;

	// Max Scale
	UPROPERTY(EditAnywhere)
	float MaxScale;

	// Speed
	UPROPERTY(EditAnywhere)
	float Speed;

	// 일정 기간이 지났을 때 얼마나 속력을 증가시킬지(속도의 증가치)
	UPROPERTY(EditAnywhere)
	float AmountOfAddSpeed;

	// 몇초간 누르고 있어야 속력이 상승하는지를 정의
	UPROPERTY(EditAnywhere)
	float TimeToSpeedUp;

	// 시작 Speed
	float StartSpeed;

	// 키보드를 몇초간 누르고 있는 중인지
	// 키보드에서 손 떼면 0으로 초기화
	float ElapsedTime;

	// 키보드를 누르고 있는 중인가?
	// true이면 누르고 있는 중이고, false이면 안누르고 있는 중
	bool bPressing;
};

< 헤더(.h) 파일 >

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


#include "MyPawn.h"
#include "Camera/CameraComponent.h"

// Sets default values
AMyPawn::AMyPawn()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	// 이 폰을 가장 빠른 번호의 플레이어가 조종하도록 설정합니다.
	AutoPossessPlayer = EAutoReceiveInput::Player0;

	// 무언가를 붙일 더미 루트 컴포넌트를 만듭니다.
	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
	// 카메라와 보이는 오브젝트를 만듭니다.
	UCameraComponent* OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("OurCamera"));
	OurVisibleComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("OurVisibleComponent"));
	// 루트 컴포넌트에 카메라와 보이는 오브젝트를 붙입니다. 카메라를 이동 및 회전시킵니다.
	OurCamera->SetupAttachment(RootComponent);
	OurCamera->SetRelativeLocation(FVector(-250.0f, 0.0f, 250.0f));
	OurCamera->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));
	OurVisibleComponent->SetupAttachment(RootComponent);

	// Speed 초기화
	Speed = 100.0f;
	StartSpeed = Speed;

	ElapsedTime = 0.0f;
	bPressing = false;
}

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

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

	// "Grow액션에 따라 키우고 줄이는 것을 처리함
	{
		float CurrentScale = OurVisibleComponent->GetComponentScale().X;

		if (bGrowing && !CurrentVelocity.IsZero() && !bPressing) 
		{
			CurrentScale = MaxScale;
		}
		else if (bGrowing)
		{
			CurrentScale += DeltaTime;
		}
		else
		{
			CurrentScale -= (DeltaTime * 0.5f);
		}

		CurrentScale = FMath::Clamp(CurrentScale, 1.0f, MaxScale);
		OurVisibleComponent->SetWorldScale3D(FVector(CurrentScale));
	}

	// "MoveX"와 "MoveY" 축에 따라 이동을 처리합니다.
	{
		if (!CurrentVelocity.IsZero())
		{
			FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
			SetActorLocation(NewLocation);

			ElapsedTime += DeltaTime;

			if (ElapsedTime >= TimeToSpeedUp)
			{
				Speed += AmountOfAddSpeed;
				ElapsedTime = 0.0f;

				bPressing = bPressing == false ? true : false;
			}
		}
		else
		{
			if (bPressing)
			{
				bPressing = false;
				ElapsedTime = 0.0f;

				Speed = StartSpeed;
			}
		}
	}
}

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

	InputComponent->BindAction("Grow", IE_Pressed, this, &AMyPawn::StartGrowing);
	InputComponent->BindAction("Grow", IE_Released, this, &AMyPawn::StopGrowing);

	InputComponent->BindAxis("MoveX", this, &AMyPawn::Move_XAxis);
	InputComponent->BindAxis("MoveY", this, &AMyPawn::Move_YAxis);
}

void AMyPawn::Move_XAxis(float AxisValue)
{
	CurrentVelocity.X = FMath::Clamp(AxisValue, -1.0f, 1.0f) * Speed;
}

void AMyPawn::Move_YAxis(float AxisValue)
{
	CurrentVelocity.Y = FMath::Clamp(AxisValue, -1.0f, 1.0f) * Speed;
}

void AMyPawn::StartGrowing()
{
	bGrowing = true;
}

void AMyPawn::StopGrowing()
{
	bGrowing = false;
}

< 구현부(.cpp) 파일 >

오늘 하면서 알게된 점

키를 바인딩하고 키 입력에 따라 적절한 함수를 실행시키는 방법 
→ 키 입력이 게임의 가장 핵심이기 때문에 제일 알찼던 튜토리얼이었음!