이 문서에는 언리얼엔진을 이용한 나의 설계 경험을 정리한다.

(문서의 내용은 결정된 내용이 아니고, 지속적으로 개선될 것이다.)

언리얼 엔진 C++ 개발의 기본적인 프로그래밍 컨벤션은 다음 문서를 참고한다.

docs.unrealengine.com/en-US/ProductionPipelines/DevelopmentSetup/CodingStandard/index.html

Coding Standard Standards and conventions used by Epic Games in the Unreal Engine 4 codebase. docs.unrealengine.com

게임 내 커스텀 Enum 데이터 타입들을 모아놓을 클래스 파일을 생성한다.

언리얼 작업중에는 직접 제작한 다양한 열거형 타입들을 사용하게 될 것이다.

이 데이터 타입들 중에서는 특정 클래스에 귀속되어야하는 타입도 존재하겠지만, 글로벌하게 사용되는 공통 데이터 타입들도 분명 존재한다. 그리고 구현 단계에서는 그 경계를 명확히 지정하기 어렵기 때문에 playground로서의 클래스파일이 하나 필요하다.

ex)

// 빈 클래스class DataTypes
{
public:
	DataTypes();
	~DataTypes();
};

UENUM(BlueprintType)
enum class EEnemyAIType : uint8
{
    Tank           UMETA(DisplayName = "Tank"),
    Healer         UMETA(DisplayName = "Healer"),
    Ranged         UMETA(DisplayName = "Ranged"),
    Rusher         UMETA(DisplayName = "Rusher"),
    Disabler       UMETA(DisplayName = "Disabler")
};

UENUM(BlueprintType)
enum class EGameState : uint8
{
    MainMenu                UMETA(DisplayName = "MainMenu"),
    LevelSelectionMenu      UMETA(DisplayName = "LevelSelectionMenu"),
    LoadingScreen           UMETA(DisplayName = "LoadingScreen"),
    LoadOutMenu             UMETA(DisplayName = "LoadOutMenu"),
    InGameHUD               UMETA(DisplayName = "InGameHUD"),
    MissionSummary          UMETA(DisplayName = "MissionSummary"),
    Unassigned              UMETA(DisplayName = "Unassigned"),
};

// ...

게임 내 커스텀 Struct 데이터 타입들을 모아놓을 클래스 파일을 생성한다.

열거형과 마찬가지의 이유로 구조체도 따로 모아놓을 클래스 파일이 필요하다.

class CustomStructs
{
public:
	CustomStructs();
	~CustomStructs();
};

USTRUCT(BlueprintType)
struct FBossAIData
{
    GENERATED_BODY()

public:
    FBossAIData()
        :
        AIType(EEnemyAIType::Tank)
    {}

    FBossAIData(EEnemyAIType InAIType, FName InDataTableRowName)
        :
        AIType(InAIType),
        DataTableRowName(InDataTableRowName)
    {}

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        EEnemyAIType AIType;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FName DataTableRowName;
};

// ...

게임 내 유틸리티 함수를 모아놓을 클래스를 생성한다.

언리얼에서 작업을 진행하게 되면, 굉장히 많은 기능들과 방대한 코드 속에서 그때그때 예제를 만들며 많은 시간을 낭비하게 된다. 시간을 좀 더 효율적으로 활용하기 위해 제작해본 예제들을 기능 단위로 유틸리티 함수에 쌓아두어야 할 것이다.

유틸리티 함수는 일반화된 작업들을 수행하는 함수들로, 모두 static함수로 구성되어 있다.

화면에 직선이나 구체를 그리는 디버깅용 함수, Enum을 문자열로 변환하는 함수, 템플릿 함수 등이 이 클래스의 함수로서 들어가게 될 것이다.

ex)

class GameUtils
{
public:
    GameUtils() {}
    ~GameUtils() {}

public:
// logsstatic void PrintHitResult(const FHitResult& InHitResult);

    static bool IsValid(const UObjectBase* const InObject);
    static FString GetDebugName(const UObject* const InObject);

    static void DrawPoint(UWorld* InWorld, FVector InLocation, FColor InColor = FColor::Red);
    static void DrawArrow(UWorld* InWorld, FVector InStart, FVector InEnd);

    template<typename Type>
    static Type GetRandomArrayElement(const TArray<Type>& InArray)
    {
        int Index = FMath::RandRange(0, InArray.Num() - 1);
        return InArray[Index];
    }

    template<typename TEnum>
    static FORCEINLINE FString GetEnumValueAsString(const FString& InEnumName, TEnum InEnumValue)
    {
        const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *InEnumName, true);
        if (!EnumPtr) return FString("Invalid");
        return EnumPtr->GetNameByValue((int64)InEnumValue).ToString();
    }

// ...
};

GameInstance의 역할