본문 바로가기
언리얼엔진

언리얼 엔진5 C++ 정리 1편

by 대니스 2022. 8. 8.

C++ 클래스 생성

1. 툴 -> 새로운 C++ 클래스

2. 콘텐츠 브라우저 -> C++ 클래스 폴더 -> ADD 또는 우클릭해서 새 C++ 클래스 항목

 

헤더 파일 : 클래스를 선언하고 클래스에 속하는 변수와 함수의 원형을 선언하는 용도의 파일

소스 파일 : 헤더 파일의 함수를 구현

 

클래스 이름과 같은 이름을 가진 생성자

: 클래스의 객체가 생성될 때 한 번 호출 되는 함수

: 주로 생성된 액터의 프로퍼티, 즉 변수의 기본 값을 설정해주는데 사용된다.               

 

BeginPlay 함수

: 액터가 배치된 월드에서 게임이 시작되거나 액터가 월드에 스폰되었을 때 한 번 호출되는 함수

: 게임플레이 로직을 초기화시키는데 사용

 

Tick 함수

: 매개변수인 DeltaTime을 통해서 Tick함수가 지난 번에 호출된 이후로 시간이 지난 후 다시 Tick 함수가 호출되었는지에 대한 시간을 전달 받을 수 있음.

: Actor가 활성화되어 있는 동안 계속해서 호출되기 때문에 주로 게임의 로직을 처리하는 기능을 구현

 

기본 이벤트 함수 호출 확인

UE_LOG : 로그를 남기기 위해서 쓰이는 함수 (.h) (ex. UE_LOG(LogTemp, Log, TEXT("Hello world")) )

->ctrl+Alt+f11 : 컴파일 진행

 

변수 선언 방법

UPROPERTY() (.h)

: 변수 값을 에디터에서 사용하기 위해서 붙이는 매크로

: 프로퍼티가 언리얼 엔진 및 에디터에서 이러한 프로퍼티가 있음을 알림

: 연결되었을 때 어떻게 작동할지를 지정하기 위한 것

 

Fstring (.h)

: 저장되는 글자의 길이에 따라서 변수의 길이가 자동으로 달라지는 타입으로 C++ string과 유사

: ex. TEXT("text")

 

변수를 에디터에서 보이게 만들기

UPROPERTY()에서 프로퍼터를 이용해서 만들기

(ex. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage"))

-EditAnywhere : 아키타입(인스턴스화되지 않은 블루프린트의 원본)과 레벨에 배치된 인스턴스 양 쪽 모두의 프로퍼티 창에서 편집할 수 있음.

-BlueprintReadWrite : 블루프린트에서 읽기와 쓰기가 모두 가능하다는 뜻

-Category="Damage" : 블루프린트 편집 툴이나 디테일 패널에서 이 포로퍼티를 Damage라는 카테고리로 묶어서 보여줌.

-BlueprintReadOnly : 프로퍼티를 블루프린트에서 읽기만 가능함

-VisibleAnywhere : 프로퍼티를 모든 프로퍼티 창에서 보이지만 편집할 수 없게 함.

-Transient : 해당 프로퍼티가 휘발성 프로퍼티로 저장되지 않음을 의미

 

변수의 기본 값 설정하기 

프로퍼티를 초기화하는 방법 (.cpp)

1. 생성자 옆에 콜론을 입력한 뒤 프로퍼티의 이름을 적고 괄호에 기본 값을 넣기

(ex. AMyActor::AMyActor : TotalDamage(10), DamageTimeInSeconds(1.2f))

2. 생성자의 바디에서 기본 값을  대입

 

함수 호출하기

PostInitProperties

: 오브젝트의 변수가 초기화될 때 호출되는 함수 (Post다음에 대문자 i 다.)

: 소스 파일 내에 함수의 내용에 Super::PostInitProperties 함수를 호출하게 만든다. (Super 키워드는 클래스가 상속받은 부모 클래스에 있는 원본 프로퍼티나 함수를 가져오는데 사용되는 키워드)

PostEditChangeProperty

: 변수가 수정될 때 호출되는 함수 

: 이 두 함수는 AMyActor의 부모 클래스인 AAcotr에서 상속받는 함수이기 때문에 부모 클래스의 함수를 자식 클래스인 AMyActor에서 덮어쓴다는 의미로 virtual 키워드와 override 키워드를 사용해줘야한다.

: 소스 파일 내에 함수의 내용에 Super::PostEditChangeProperty(PropertyChangedEvent) 함수를 호출하게 만든다. 

: 호출하려는 함수가 먼저 호출해야 한다.

-ex. virtual void PostInitProperties() override; (.h)

       virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; (.h)

 

-소스 파일에서 함수를 작성

1. 직접 작성

2. 초록색 밑줄이 그어진 함수 이름에 커서를 두고 [ctrl + . ] 단축키를 누르고 [PostInitProperties에서 'AMyActor.cpp' 정의 만들기]를 선택

                                         

함수를 블루프린트에서 호출할 수 있게 만들기

UFUNCTION : 매크로를 사용하면 함수를 블루프린트에서 사용할 수 있게 설정하는 등의 기능을 지정자로 넣을 수 있다.

BlueprintCallable

: 지정자를 넣어주면 해당 함수를 블루프린트에서 사용할 수 있게 된다.

: 블루프린트에서 사용할 모든 함수에는 카테고리를 할당해줘야만 정상적으로 호출 할 수 있게 된다.

 

액션 입력과 축 입력

액션 입력 : 간단하게 눌렀다가 떼는 입력

축 입력 : 연속적인 값을 가지는 입력

입력 맵핑

: 입력 추가 -> 입력 이름 -> 키 추가

: 맵핑을 한 뒤에는 기능을 바인딩해야 한다. 

 

기능 구현과 바인딩

1. 편집 -> 프로젝트 세팅 -> 엔진 섹션 -> 입력

2. 바인딩 섹션을 보면 액션 매핑과 축 매핑을 볼 수 있는데 거기서 입력할 키와 기능을 추가

3. 툴 -> 새로운 C++ 클래스 -> 폰 (폰은 언리얼 엔진에서 AI나 플레이어가 조작할 수 있는 오브젝트)

4. 헤더 파일과 소스 파일은 아래와 같이 작성

헤더 파일

// 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 FIRSTCPP_KR_API AMyPawn : public APawn
{
	GENERATED_BODY()

public:
	FVector CurrentVelocity;

	bool bGrowing;

	UPROPERTY(EditAnywhere)
	USceneComponent* OurVisibleComponent;

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 MoveForward(float AxisValue);

	void MoveRight(float AxisValue);

	void StartGrowing();
	
	void StopGrowing();
};

소스 파일

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


#include "MyPawn.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;

	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
	OurVisibleComponent = CreateDefaultSubobject<USceneComponent>(TEXT("VisibleComponent"));
	OurVisibleComponent -> SetupAttachment(RootComponent);

}

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

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

	{
		float CurrentScale = OurVisibleComponent->GetComponentScale().X;
		if (bGrowing)
		{
			CurrentScale += DeltaTime;
		}
		else
		{
			CurrentScale -= (DeltaTime * 0.5f);
		}
		CurrentScale = FMath::Clamp(CurrentScale, 1.0f, 2.0f);
		OurVisibleComponent->SetWorldScale3D(FVector(CurrentScale));
	}

	{
		if (!CurrentVelocity.IsZero())
		{
			FVector NewLocation = GetActorLocation() + (-CurrentVelocity * DeltaTime);
			SetActorLocation(NewLocation);
		}
	}

}

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

	InputComponent->BindAxis("MoveForward", this, &AMyPawn::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &AMyPawn::MoveRight);

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

}

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

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

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

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

5. 폰에서 블루프린트 생성 -> 액터를 루트에 생성 -> 액터를 찍을 카메라 컴포넌트 생성

6. 게임모드 블루프린트 생성 -> 월드 세팅에서 GameMode Override에 만들어진 블루프린트 적용

 

위의 정리는 베르의 게임 개발 유튜브에서 정리하였음을 알려드립니다.