Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part01/Chapter04 Done #30

Merged
merged 1 commit into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions Document/StudyNote/UnrealLecture/Part1/Lecture4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# 4강: 언리얼 오브젝트 기초

- 강의 목표
- 게임 프로그래밍이 가지는 **특수성**과 **언리얼 오브젝트의 필요성**의 이해
- 언리얼 오브젝트의 선언과 엔진 **내부 컴파일 과정**의 학습
- 강의 과제
- 모던 객체 지향 설계 원칙 SOLID에 대해 조사해 정리해보시오.
각 원칙 별로 예제가 있으면 더 좋습니다.
- Clean Code에 들어본 적이 없다면 추가로 정리해보세요. 장기적으로 책을 읽으며 정리해도 좋고, 누군가 정리해둔 글을 읽어도 좋습니다.

과제는 과거에 읽은 [클린코드](https://github.com/fkdl0048/BookReview/issues/58), [객체지향의 사실과 오해](https://github.com/fkdl0048/BookReview/issues/40), [객체지향 사고 프로세스](https://github.com/fkdl0048/BookReview/issues/36), [오브젝트](https://github.com/fkdl0048/BookReview/issues/209) 복습으로 대체하여 진행

- [언리얼 오브젝트 공식 문서](https://docs.unrealengine.com/5.3/ko/objects-in-unreal-engine/)

## 게임 프로그래밍의 특수성

- 사용자: 쾌적한 경험을 위해 단일 컴퓨터에서 최대 성능을 뽑아 내야 한다.
- 개발자: 게암의 규모가 커질수록 방대하고 복잡한 기능을 안정적으로 관리해야 한다.

게임 특성상 메모리에 접근하여 최대의 성능을 뽑아야 하기에 주로 C++로 개발이 된다. 하지만 매우 과거의 언어라는 특성과 장점이자 단점인 메모리 접근으로 인해 이후에는 하이레벨의 객체지향 언어들이 개발이 되었다. (C#, Java)

## 객체지향 설계 원칙 (SOLID)

SOLID라는 원칙으로 불리는데, 나는 개인적으로 이 원칙을 이해하고 활용하기 까지 정말 오래걸린 것 같다. 객체지향에 대한 감을 잡기위해 책도 많이 읽고 적용도 해봤지만, 단순하게 SOLID를 외우는 것이 아닌 객체지향 세계에서 협력을 구성하면 나타나는 형태라고 보면 좋을 것 같다. (리스코프 치환 제외)

예를 들어 SRP를 준수하게 되면 자동적으로 Open/Close 원칙이 지켜지게 되고 뒤이어 인터페이스 단일과 분리도 지켜지게 된다.

후발언어들은 인터페이스, 리플렉션, 델리게이트라는 기능들을 추가하고 더욱 고도화되고 있다.

*최근에 알게된 믹스인이라는 기능도 지원하는지 궁금하다.*

게임에서도 마찬가지로 불확실성과 오랜 개발기간, 서비스기간이 필요하기 때문에 자연스럽게 객체지향의 필요성이 높아지게 되면서 언리얼엔진은 C++의 매크로 기능을 활용하여 원칙을 쉽게 준수할 수 있는 환경을 만들었다.

*C++도 배워야 하고, 언리얼 C++도 배워야 한다.*

## 언리얼 오브젝트

언리얼 오브젝트란 언리얼이 설계한 새로운 시스템의 단위 오브젝트(객체)이다. 일반 C++ 오브젝트와 언리얼 오브젝트의 두 객체 모두 사용할 수 있으며, 구분을 위해 일반 C++ 오브젝트는 `F`, 언리얼 오브젝트는 `U`접두사를 사용한다.

주로 C++오브젝트는 저수준의 빠른 처리를 위한 기능 구현에 사용된다. 즉, 언리얼 오브젝트 내부에서 합성형태로 주로 사용하거나 File시스템을 다루는 등에 사용된다. 반면, 언리얼 오브젝트는 콘텐츠 제작과 관련된 복잡한 구조에 사용된다.

실제 코드레벨에선 `UCLASS`라는 매크르를 붙여서 사용하는데 이를 통해 `Uobject`에서 파생된 클래스에 태그를 지정하여 실질적인 `Uobject`로써 활용이 가능하다. 이는 CDO라는 클래스 디폴트 오브젝트라는 하나의 오브젝트를 유지한다고 한다. (다음강의에서 설명)

대부분의 객체들은 readOnly규약을 따르지만 `GetClass()`함수를 통해 액세스가 가능하다. (GetComponet..?)

모든 `Uobject`는 생성자 실행인자를 지원하지 않으며 엔진 시작 시 초기화된다. (디폴트 생성자 호출, 이게 없으면 컴파일이 되지 않음) 이 생성자는 가벼워야 하며, 디폴트값과 서브오브젝트를 구성하는 데에만 사용해야 한다. 직접적인 라이프서클에 로직을 태우고 싶다면 액터, 액터 컴포넌트의 `BeginPlay()`함수를 사용하면 된다. (Part2 에서 사용)

### 지원하는 기능

기본적으로 가비지 콜렉션을 지원한다. 이 말은 너무 세세한 부분까지 메모리를 관리하지 않아도 되고 반복적인 메모리할당 해제가 필요한 곳에서는 직접적인 관리가 가능해진다는 말로 `C++`의 단점을 해소할 수 있다. 리플렉션 및 직렬화 등등 대부분의 고수준 객체지향 언어에서 지원하는 기능들은 지원한다.

이러한 기능을 활용하려면 해당 타입에 대한 헤더 파일에 전처리 단계를 실행해야 하며 이를 `UnrealHeaderTool`에서 수행한다.

### 주요한 특징

- 클래스 기본 객체(CDO): 클래스의 기본 값과 타입 정보의 제공
- 리플렉션(Reflection): 런타임에서 클래스 정보의 참조 기능
- 인터페이스(interface): 모든 객체 지향 언어가 제공하는 인터페이스의 제공
- 향상된 열거형: 보다 향상된 열거형 지원
- 델리게이트(Deligate): 객체간의 결합을 낮출 수 있는 델리게이트 기능의 제공
- 가비지컬렉션(Garbage Collection): 자동 메모리 관리
- 향상된 구조체(Struct): 리플렉션이 가능한 구조체의 지원
- 직렬화(Serialization): 객체의 정보를 바이트 스트림으로 저장, 전송, 불러들이는 기능

## 언리얼 오브젝트의 선언

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

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyObject.generated.h"

/**
*
*/
UCLASS()
class UNREALOBJECT_API UMyObject : public UObject
{
GENERATED_BODY()

};
```

가장 기본이 되는 언리얼 오브젝트를 생성했을 때의 헤더파일이다. `CoreMinimal.h`와 `UObject/NoExportTypes.h`는 기본적인 헤더파일이다.

유니티와 다른 점은 파일이름과 실제 클래스 이름이 일치하지 않고 접두사를 사용하여 해당 객체의 특성을 밝힌다. (C++은 F, 언리얼은 U)

`UCLASS`매크로를 통해 해당 클래스가 언리얼 오브젝트임을 명시한다. `UNREALOBJECT_API`라는 `프로젝트이름_API`로 이 클래스가 다른 모듈에서도 사용될 수 있도록 한다. (공개)

*C#은 namespace를 사용하여 모듈을 구분하며, 유니티는 어셈블리를 사용한다.*

`GENERATED_BODY`매크로는 `"MyObject.generated.h"`파일의 사용할 부분을 지정해준다. 이는 해당 파일의 구조와 라인수를 매크로를 통해 헤더파일에 추가해준다. 이런 기능들은 앞서 말한 객체지향을 좀 더 효율적으로 구현하기 위한 매크로나 함수들이다.

실제 내부에선 프로젝트 이름 및 라인 수를 계산하여 헤더파일과 연결하기에 줄수만 바뀌어도 다시 컴파일 해야 한다. 초기에 헤더파일의 수정은 에디터를 꺼야하는 이유가 여기에 있다. (상당히 정적인 느낌이 든다.)

이 역할을 하는 매크로는 `UnrealHeaderTool`이라는 툴을 통해 처리된다.

정리하자면 언리얼 오브젝트의 코드를 분석하는 단계에서 바로 컴파일 되는 것이 아닌 `UnrealHeaderTool`을 통해 헤더파일을 처리하여 컴파일을 진행한다.

## 정리

- 게임이 대형화되면서 성능과 유지보수 두 가지 모두 중요하다.
- 언리얼 엔진은 C++ 언어를 확장한 언리얼 오브젝트라는 객체 구조를 고안함
- 지정된 매크로를 사용해 빌드를 수행하면, 추가 코드가 자동으로 만들어지는 구조를 가짐
- 언리얼 오브젝트를 사용해 대규모 게임 제작을 안정적으로 설계하고 구현할 수 있음
2 changes: 1 addition & 1 deletion Document/StudyNote/UnrealLecture/Part1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- [1강: 헬로 언리얼!](./Lecture1.md)
- [2강: 언리얼 C++ 코딩 규칙](./Lecture2.md)
- [3강: 언리얼 C++ 기본타입과 문자열](./Lecture3.md)
- 4강: 언리얼 오브젝트 기초
- [4강: 언리얼 오브젝트 기초](./Lecture4.md)
- 5강: 언리얼 오브젝트 리플렉션 시스템 I
- 6강: 언리얼 오브젝트 리플렉션 시스템 II

Expand Down
13 changes: 13 additions & 0 deletions Unreal5_Lecture_Project/Part1/UnrealObject/.vsconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": "1.0",
"components": [
"Microsoft.Net.Component.4.6.2.TargetingPack",
"Microsoft.VisualStudio.Component.VC.14.36.17.6.x86.x64",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Microsoft.VisualStudio.Component.Windows10SDK.22000",
"Microsoft.VisualStudio.Workload.CoreEditor",
"Microsoft.VisualStudio.Workload.ManagedDesktop",
"Microsoft.VisualStudio.Workload.NativeDesktop",
"Microsoft.VisualStudio.Workload.NativeGame"
]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"BuildId": "27405482",
"Modules":
{
"UnrealObject": "UnrealEditor-UnrealObject.dll"
}
}
Loading