배움 저장소

[UE4] Programming KickStart 본문

Dev/Unreal Engine4

[UE4] Programming KickStart

시옷지읏 2021. 10. 28. 01:14

 

 

Programming Kickstart - Unreal Engine

In this course, you’ll learn about programming in Unreal Engine along with tips and tricks for creating and developing C++ projects.

www.unrealengine.com

강의를 보고 정리한 글이다

Programming_poster_18x24.pdf
1.29MB

 

 

BaseType


1. String

Fstring : Normal

Fname : Actor Name처럼 Unique 입력값을 위해 사용한다.

Ftext : 다양한 언어에서 Localize 사용한다. 엔진에서 FText 찾아서 모아줘서 Localize할 때 편하다.

 

이때 FName이 Unique한 값을 사용한다고 해서 테스트해보았다.

// Test.h
	FString test_string = TEXT("Test");
	FString test_string2 = TEXT("Test");

	FName test_name = TEXT("Name");
	FName test_name2 = TEXT("Name");
    
// Test.cpp
	UE_LOG(LogTemp, Display, TEXT("%s"), *test_string);
	UE_LOG(LogTemp, Display, TEXT("%s"), *test_string2);
	UE_LOG(LogTemp, Warning, TEXT("%s"), *test_name.ToString());
	UE_LOG(LogTemp, Warning, TEXT("%s"), *test_name2.ToString());

FName이 중복된 Text를 허용하지 않을 것 같았지만 컴파일, 실행할 때 모두 문제가 없어 당황스러웠다.

 

FName

 

docs.unrealengine.com

위 문서에서 그 답을 알 수 있었다. FName은 주로 Content Browser에서 여러 Asset의 이름으로 사용된다. Map이나 Dictionary 같은 형태로 사용되기 때문에, FName의 String과 Index로 대응하여 사용된다. 그래서 FName은 재사용되어도 Data Table에는 한 번만 저장된다.  

 이 때 주의할 점은 FName은 대소문자 구분을 하지 않는다 ( Case Insensitive ).

 

- 공식 문서에서 FName의 값을 할당할때 FName()을 사용하고 있다.

// 1. Initialize
FName TestHUDName = FName(TEXT("ThisIsMyTestFName"));

// 2. FString to FName
FName TestHUDName = FName(*TestHUDString); // Case Insensitive

// 3. FText to FName
Error("Impossible!");

// 4. Comparision
CompareFloat = TestName.Compare(OtherFName)

- 주의 ! 2번째 경우 FName은 대소문자 구분을 하지 않기 때문에 FString의 대소문자 정보를 잃어버린다.

- FName의 비교는 String끼리 비교하지 않고 Index끼리 비교하기 때문에 성능이 좋다.

 

참고

 

MakeUniqueObjectName

Create a unique name by combining a base name and an arbitrary number string.

docs.unrealengine.com

 

FName의 실사용 예시

FRotator rotPelvis = Mesh->MeshGetInstance(this))->GetBoneRotation(FName(TEXT("pelvis")));

Skeletal Mesh Component는 수 많은 Bone을 가지고 있다. 이때 FName을 사용하면 사용자는 TEXT로 불러올 수 있어 편리하고 엔진은 Hash Table에서 Index를 바로 가져올 수 있다.

 

FName HashTable에서 특정 FName을 검색하기

	UE_LOG(LogTemp, Warning, TEXT("%s"), *test_name.ToString());
	
	if (FName(TEXT("Name"), FNAME_Find) != NAME_None)
	{
		UE_LOG(LogTemp, Display, TEXT("Already Exsist!"));
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("%s"), *test_name2.ToString());
	}

따라서 맨 위 FName의 중복을 확인하고 싶으면 FName 함수의 Overloading을 사용하면 된다.

2. Collections

TMap,

TArray : Vector 안에 Vector처럼 사용할 없다. TArray안에 TArray 넣을 없다.

TSet

 

UObject 상속한 객체는 모두 Garbage Collecter 관리대상이다.

Actor :  Level 위에서 존재하는 모든 객체는 Actor이며, Transform 가지고 있다.

Components: Transform 가지지 않는 객체로 Actor 기능을 더해줄 있다.

 

Garbage Collection 탭에서 확인할 수 있다.

 

 

Actor Lifecycle

What actually happens when an Actor is loaded or spawned, and eventually dies.

docs.unrealengine.com

- Level에서 Actor가 파괴되었다면 Garbage Collector의 수집 대상이다. 그리고 Freeing Resources.

 

 

3. Smart Pointers

TWeakPtr, :

TSharedPtr :

TSharedRef :

ㄴTUniquePtr :

 Garbage Collecter는 위의 스마트 포인터를 이용하여 Memory를 관리한다. 

이때 스마트 포인터란 무엇일까?

 

smart pointers - cppreference.com

Warning: This wiki is part of the deprecated and unmaintained CppReference Book project. For up-to-date information on C++, see the main reference at cppreference.com. Smart pointers are used to make sure that an object is deleted if it is no longer used (

en.cppreference.com

 포인터에 new 키워드를 사용하여 값을 할당한다. 그리고 포인터를 delete 하기 전에 return키워드가 호출되었다면 Memory Leak가 발생한다.

 unique_ptr을 사용하면, unique_ptr이 삭제될 때 자동으로 할당되어 있는 값을 삭제해주니 Memory Leak 걱정을 하지 않아도 된다.

 

4. Creation & Destruction

- Actor는 코드로 생성해서 코드로 삭제할 수 있다.

- Object는 반드시 Garbage Collecter가 삭제하도록 만들어야 한다. 발표자가 반드시(Should be)라고 했는데 왜 그런지는 설명하지 않는다.

 Object의 예로 Skeletal Mesh가 있다. 만약 level 1에서 사용한 캐릭터의 Skeletal Mesh가 Level2에서 더이상 사용되지 않는다면 Unreferenced되어있는 캐릭터의 Skeletal Mesh를 Garbage Collecter가 찾아낼 것이다. 어떻게 찾아내는지는 다음의 Garbage Collection 탭에 나타나 있다.

 

Unreal Object Handling

Overview of the features of the UObject system.

docs.unrealengine.com

 개인적인 생각엔, Tree에 등록되어있는 Object Node가 삭제되면 nullptr에서 ->연산자를 사용하게 되기 때문에 금지할 거 같다. 

 

5. Macros and Specifiers

Specifier는 코드로 구현되어있는 기능과 특정 값을 디자이너가 접근할 수 있게 해준다.

UCLASS()
class ATestCharacter : public ACharacter
{
// Macros
UPROPERTY()
float VExam_Zero
// Macros and Specifiers
UPROPERTY(EditAnywhere, BlueprintReadWirte, Category = Combat)
float VExam_One;


UFUNCTION()
void FuncExam();

GENERATED_BODY()
};

Specifiers를 통해 언리얼 엔진 에디터에서 수정, 읽기가 가능한지 나타낼 수 있다. 이때 Category도 설정할 수 있다.

언리얼 에디터 내 블루프린트 내에서 읽기, 수정 이 가능한지도 설정가능하다.

https://docs.unrealengine.com/4.26/en-US/ProgrammingAndScripting/GameplayArchitecture/Properties/Specifiers/

https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/GameplayArchitecture/Functions/Specifiers/

https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/GameplayArchitecture/Classes/Specifiers/

https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/GameplayArchitecture/Structs/Specifiers/

 개인적으로 Classes와 Struct의 Specifier를 사용해본 적은 없다. Function Specifier는 블루프린트에서 특정함수를 호출하고 싶을 때 사용했고, Properties는 값을 바꾸며 게임을 테스트해보는 과정에서 자주 사용했다.

 

UFUCTION()
/*
BlueprintPure  -> transfer c++ function to pure BP function, So no needs to flow to call it
			   -> Usually for Constant Function
BlueprintType  -> You can spliting Structure to each ones
EditInlineNew / Instanced -> Not referencing, Just Get the Instanced Class.
CallInEditor
*/

 

6. Data Object

ㄴ DataTables

ㄴ DataAssets

ㄴ Curves

Machine Learning을 사용할때 유용하게 사용할 거 같다.

 

튜토리얼

 

Memory


1. Life Cycle Of Actors

굳이 아래 문서를 읽어볼 필요는 없다. Actor는 Constructor -> BeginPlay -> InitalizeComponments 순으로 동작한다.

 

 

Actor Lifecycle

What actually happens when an Actor is loaded or spawned, and eventually dies.

docs.unrealengine.com

 신기하게도 Actor Lifecycle을 가져와서 Pending Kill 개념을 이야기하고 있다. Pending Kill은 Object를 Code로 삭제할 수 없기 때문에 Deference로 표시해놓고 후에 Garbage Collecter가 삭제하라고 표시해놓은 것이다. Pending Kill 되어있는 Actor에 접근하면 Deference가 풀리기 때문에 후에 삭제 되지 않으니 주의해야한다.

 아마 Actor를 삭제할 때 더 이상 사용하지 않는 Object를 지우기 때문에 Pending Kill 개념을 Actor Life Cycle에서 설명한 것 같다.

 

 

GamePlay FrameWork


PDF 파일 참고

ㄴ GameMode

- 게임 레벨 개념

- Server에 존재하며 Client는 접근 불가능하다.

- 게임 진행정도는 GameState로 공유한다.

- PlayerState로 Client 간 정보 교환이 가능하다.

 

ㄴ PlayerController

- User와 관련있는 기능을 이곳에다 구현한다. UI를 예를 들 수 있다.

1. Controller 입력값을 설정할 수 있다. ex) RTS게임에서 Mouse 입력을 받아 바로 캐릭터에 명령을 내린다. 

2. Character에서 Controller를 불러와 입력값을 설정할 수 있다. ex) 캐릭터 마다 다른 입력값을 받는 게임

3. Actor에 Actor Component를 붙여서 입력값을 설정할 수도 있다. 데미지 기능도 Component로 하면 편하다. 

 

ㄴ Subsystem

- 언리얼 엔진과 에디터를 외부에서 사용할 수 있도록 Instancing하였다.

- LifeCycle이 Parent를 따라가기 때문에 여러 복잡한 작업을 할 필요가 없다.

 

 

Else


Profileing and Debugging

FPS와 GPU Memory 사용정도를 확인가능하다.

cmd  >> stat FPS

cmd >> profileGPU

 

AsyncTask 

- 코드가 동기적으로 작동하면 항상 순서대로 코드가 실행된다. 비동기적으로 작업하면 코드가 병렬적으로 작동한다. 따라서 AsyncTast를 사용하면 게임 정보를 매 프레임 업데이트하는 Tick과 화면을 출력할 수 있게 Rendering 하는 과정을 방해하지 않고 별도의 작업을 병렬로 진행할 수 있다.

- Main Thread가 아닌 Sub Thread에서 실행된다.

-주로 UI를 구현할 때, Save 파일을 만들 때 쓴다.

Live++

- 컴파일 하지 않고 게임 실행 도중에 컴파일하여 업데이트가 가능한 기능. 쩐다.

 

Tips


1. 프로젝트를 모듈화하기

- 컴파일 시간이 줄어든다

- 다음 프로젝트에 쉽게 사용할 수 있다.

2. Live++를 계속 사용하기

- 컴파일 하면서 기다리지 않아도 된다.

3. Plugin은 Active/DeActive가 가능하다.

- 필요하지 않을 때 DeActive하자.

4. 게임 화면상에 나오는 모든 String은 FText 타입으로 작성되어야 Localization이 된다.

 

Team 작업시

- Source, Content, Config는 모두가 공유한다.

- Binaries는 프로그래머가 관리한다.

 

 

Ticking

1. 사용하지 않는 Tick은 false 설정해준다.

2. 모든 Actor가 Tick 함수를 호출하는 것보다 Tick Manger를 사용하자

 - 필요한 Actor를 Grouping 해서 관리하자. 

3. Tick 업데이트 갱신 시간을 조절하자

 - 매 프레임마다 Tick를 사용할 필요가 없다면 업데이트 주기를 늘리자.

 

GamePlay FrameWork

1. Pawn vs Character

- Skeletal Mesh를 가지고 있으면 Character이다.

2. Input은 BluePrint가 아닌 C++로 관리한다.

- BluePrint는 Input값을 먹어버린다? BluePrint에서 Input값 찾기 힘들다.

 

C++ vs BluePrint

1. Core는 C++로 구현하기

2. 특정 레벨(GameMode), PreFab(Collection of Object)은 BluePrint로 구현

3. Event는 C++와 BluePrint로 연결해 사용가능하다.

 

Constructer Helpers

- C++코드에서 Asset을 가져올 수 있는 방법 중 제일 쉬움

- 단점은 Asset이 referencing되면 Memory를 잡아먹음.

- Asset이 게임 시작때 부터 Memory를 작아먹을 것 

해결방법

-  포인터를 사용한다 ( DAssets subclass, UAsset pointer )

-  필요할 때마다 Memory로 불러옴

 

Build, Cook and Pack

Cook on Fly를 이용하면 따른 테스트가 가능. 특정 레벨만 테스트 가능

- DLC, Patch를 할 때 Relase 사용하기

 

 

연습문제


'Dev > Unreal Engine4' 카테고리의 다른 글

[UE4] Introduction to C++ Programming in UE4  (0) 2021.11.08
[UE4] Asset Manger and Soft Reference  (0) 2021.11.07
[UE4] Unreal Property System (Reflection)  (0) 2021.11.02
[UE4] Profiling and Optimization  (0) 2021.10.31
[UE4] UI 최적화  (0) 2021.10.30
Comments