futurelabunseen / B-JeonganLee

UNSEEN 2nd Term Learning and Project Repo.
5 stars 0 forks source link

4강: 언리얼 오브젝트 기초 #23

Closed fkdl0048 closed 4 months ago

fkdl0048 commented 4 months ago

4강: 언리얼 오브젝트 기초

과제는 과거에 읽은 클린코드, 객체지향의 사실과 오해, 객체지향 사고 프로세스, 오브젝트 복습으로 대체하여 진행

게임 프로그래밍의 특수성

게임 특성상 메모리에 접근하여 최대의 성능을 뽑아야 하기에 주로 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에서 수행한다.

주요한 특징

언리얼 오브젝트의 선언

// 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.hUObject/NoExportTypes.h는 기본적인 헤더파일이다.

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

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

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

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

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

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

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

정리