프로젝트 정리와 모듈 추가

유영준·2023년 1월 23일
0
post-thumbnail

오늘은 그동안 작업한 프로젝트를 정리하고 모듈을 추가해보겠다
사용한 예제 파일은 링크에서 받을 수 있다

프로젝트 정리

그동안은 헤더 파일과 cpp 파일이 한 폴더에 같이 존재했다

언리얼 엔진에서는 폴더에 따라 파일을 정리해주는 기능이 있다

Classes 모든 게임플레이 클래스 헤더파일이 들어감
Private 모든 cpp 파일이 들어감
Public 모든 모듈 헤더 파일이 들어감

우리는 이번에 규모가 크지 않음으로 Private 폴더와 Public 폴더로 나누도록 하겠다

프로젝트 폴더의 Source 폴더로 들어가 Private에는 cpp, Public 에는 h 파일을 넣어준다

완성하면 다음과 같다

다음 uproject 파일을 우 클릭후 Generate Visual Studio Project files 를 눌러준다

이후 비주얼 스튜디오를 켜보면 폴더가 나뉜채로 존재하게 된다


모듈 추가하기

언리얼 엔진에서는 추가로 모듈을 생성하는 기능은 제공하지 않는다

따라서 우리가 직접 모듈을 추가해야 하는데 필요한 요소는 다음과 같다

  • 모듈 폴더와 빌드 설정 파일
  • 모듈의 정의 파일

이번에는 예제에 있는 ArenaBattleSetting 폴더 안에 모두 존재하기 때문에,

ArenaBattleSetting 폴더를 Source 폴더에 넣고 다시 한번 재생성을 해준다

이제 비주얼 스튜디오에서 추가한 모듈을 빌드해주도록 설정해주어야한다

각각 게임을 빌드하는 ArenaBattle.Target.cs 와 에디터를 빌드하는 ArenaBattleEditor.Target.cs 를 수정해주자

ArenaBattle.Target.cs

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;
using System.Collections.Generic;

public class ArenaBattleTarget : TargetRules
{
	public ArenaBattleTarget(TargetInfo Target) : base(Target)
	{
		Type = TargetType.Game;
		DefaultBuildSettings = BuildSettingsVersion.V2;
		IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1;
		ExtraModuleNames.AddRange(new string[]{ "ArenaBattle", "ArenaBattleSetting" });
	}
}

ArenaBattleEditor.Target.cs

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;
using System.Collections.Generic;

public class ArenaBattleEditorTarget : TargetRules
{
	public ArenaBattleEditorTarget(TargetInfo Target) : base(Target)
	{
		Type = TargetType.Editor;
		DefaultBuildSettings = BuildSettingsVersion.V2;
		IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1;
        ExtraModuleNames.AddRange(new string[] { "ArenaBattle", "ArenaBattleSetting" });
    }
}

모듈을 추가 후 컴파일을 진행하게 되면, Binaries 폴더에 새로운 파일이 생성된다

이렇게 dll 파일이 생성되었다면 에디터가 dll 파일을 로딩하도록 수정해주어야 한다

이때 ArenaBattleSetting 모듈을 먼저 로딩하고, ArenaBattle 모듈이 ArenaBattleSetting 에 의존성을 가지게 설정할 것이다

ArenaBattle.uproject

{
	"FileVersion": 3,
	"EngineAssociation": "5.1",
	"Category": "",
	"Description": "",
	"Modules": [
		{
			"Name": "ArenaBattleSetting",
			"Type": "Runtime",
			"LoadingPhase": "PreDefault",
			"AdditionalDependencies": [
				"CoreUObject"
			]
		},
		{
			"Name": "ArenaBattle",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				"Engine",
				"UMG",
				"AIModule",
				"ArenaBattleSetting"
			]
		}
	],
	"Plugins": [
		{
			"Name": "ModelingToolsEditorMode",
			"Enabled": true,
			"TargetAllowList": [
				"Editor"
			]
		}
	]
}

이후 C++ 클래스를 생성하면 ArenaBattleSetting 모듈로 생성할수 있게 되어 있는 것을 볼 수 있다

또한 앞으로 생성하는 C++ 클래스는 헤더와 소스 파일이 나뉘어 저장된다


INI 설정을 통한 에셋 지연 로딩

이번에는 ArenaBattleSetting 모듈에 속하고 Object를 부모로 삼는 ABCharacterSetting 클래스를 만들어준다

이 클래스를 통해 INI 파일의 정보를 받고, 그것을 불러와 설정을 바꿔줄 것이다

INI 파일을 받기 위해서는 UCLASS 매크로에 config 키워드를 추가해주어야 한다

ABCharacterSetting.h

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

#pragma once

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

/**
 * 
 */
UCLASS(config=ArenaBattle)
class ARENABATTLESETTING_API UABCharacterSetting : public UObject
{
	GENERATED_BODY()
	
public:
	UABCharacterSetting();

	UPROPERTY(config)
	TArray<FSoftObjectPath> CharacterAssets;
};

ABCharacterSetting.cpp

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


#include "ABCharacterSetting.h"

UABCharacterSetting::UABCharacterSetting()
{

}

이후 config 폴더에 DefaultArenaBattleSetting 파일을 넣어준다

다음은 ArenaBattle.Build.cs 파일에 ArenaBattleSetting 모듈을 추가해준다

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class ArenaBattle : ModuleRules
{
	public ArenaBattle(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", 
			"EnhancedInput", "UMG", "NavigationSystem", "AIModule", "GameplayTasks" });

		PrivateDependencyModuleNames.AddRange(new string[] { "ArenaBattleSetting" });
    }
}

마지막으로 ABCharacter 클래스에서 불러온 모듈을 사용해 적의 에셋을 랜덤하게 불러와준다

ABCharacter.h

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

#pragma once

#include "ArenaBattle.h"
#include "GameFramework/Character.h"
#include "ABCharacter.generated.h"

DECLARE_MULTICAST_DELEGATE(FOnAttackEndDelegate);

UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{
	GENERATED_BODY()
...

private:

    ...
    
    void OnAssetLoadCompleted();

	FSoftObjectPath CharacterAssetToLoad = FSoftObjectPath(nullptr);
	TSharedPtr<struct FStreamableHandle> AssetStreamingHandle;
};

ABCharacter.cpp

#include "ABCharacter.h"
#include "ABAnimInstance.h"
#include "DrawDebugHelpers.h"
#include "ABWeapon.h"
#include "ABCharacterStatComponent.h"
#include "Components/WidgetComponent.h"
#include "ABCharacterWidget.h"
#include "ABAIController.h"
#include "ABGameInstance.h"
#include "ABCharacterSetting.h"
#include "Engine/AssetManager.h"

...

void AABCharacter::BeginPlay()
{
	Super::BeginPlay();

	auto CharacterWidget = Cast<UABCharacterWidget>(HPBarWidget->GetUserWidgetObject());
	if (nullptr != CharacterWidget)
		CharacterWidget->BindCharacterStat(CharacterStat);

	if (!IsPlayerControlled())
	{
		auto DefaultSetting = GetDefault<UABCharacterSetting>();
		int32 RandIndex = FMath::RandRange(0, DefaultSetting->CharacterAssets.Num() - 1);
		CharacterAssetToLoad = DefaultSetting->CharacterAssets[RandIndex];

		AssetStreamingHandle = UAssetManager::GetStreamableManager().RequestAsyncLoad
		(CharacterAssetToLoad, FStreamableDelegate::CreateUObject(this, &AABCharacter::OnAssetLoadCompleted));
	}
}

...

void AABCharacter::OnAssetLoadCompleted()
{
	USkeletalMesh* AssetLoaded = Cast<USkeletalMesh>(AssetStreamingHandle->GetLoadedAsset());
	AssetStreamingHandle.Reset();
	if (nullptr != AssetLoaded)
		GetMesh()->SetSkeletalMesh(AssetLoaded);
}

...

NPC 상대는 에셋이 랜덤하게 적용되는 것을 볼 수 있다

profile
토비폭스가 되고픈 게임 개발자

0개의 댓글