前提
- UnrealEngine 4.24.1 (Launcher engine)
- VisualStudio 2019
- C++プロジェクトのビルドができる環境なら何でも良い
- ある程度のUnrealC++についての知識
- UPROPERTYとはなんぞや?レベルの解説はしません
前フリ
AnswerHubで話題が出たのでサンプルを作りました
最低限動くものを目指したので、具体的な部分は各自で読み替えていただきたく
UE4.24.1で検証していますが、この内容自体はもっと前のバージョンでも適用可能です
作り方
まずC++プロジェクトを作成しておきましょう
テンプレートは何でも良いです
例では、ThirdPersonTemplate(StarterContentsあり)を使用します
設定用のClassを作る
新規C++クラスから、UObject継承クラスを1つ作成しましょう
MyGameSettings
とでもしておきます
VisualStudioに移ったら、以下のように書いておきましょう
Propertyに関しては、お好きなものをチョイスしてください
今回はActorのClassReferenceを使います
また、それぞれのUPROPERTYにconfig
と書き加えておきましょう
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyGameSettings.generated.h"
UCLASS(config=Game, defaultconfig)
class CPP424_API UMyGameSettings : public UObject
{
GENERATED_BODY()
public:
UMyGameSettings(const FObjectInitializer& ObjectInitializer);
UPROPERTY(EditAnywhere, config, Category="MyGameSettings", meta = (AllowedClasses = "Actor"))
TSubclassOf< class AActor > DefaultSpawnActor;
};
設定をProjectSettingsで編集できるようにする
ProjectSettingsに項目を追加します
Moduleロード時に登録するようにします
テンプレートからではこのModuleのクラスがないため、ここは手書きで作ることになります
(Plugin開発ではModuleが独立しているのでModuleクラスがあります)
C++のソース内に[ProjectName].h
があります(自分のProject名で置き換えてね)
これがModuleにあたります
せっかくなのでこれを使いましょう
#pragma once
#include "CoreMinimal.h"
#include "MyGameSettings.h"
#if WITH_EDITOR
// SettingsモジュールはEditor用のため、Packaging時には参照しないようにしておく
#include "ISettingsModule.h"
#include "ISettingsSection.h"
#include "ISettingsContainer.h"
#endif
#define LOCTEXT_NAMESPACE "FCustomSettingsModule"
class FCustomSettingsModule : public FDefaultGameModuleImpl
{
// モジュールロード時
virtual void StartupModule() override
{
// 設定を登録する
RegisterSettings();
}
// モジュールアンロード時
virtual void ShutdownModule() override
{
if (UObjectInitialized()) {
// 設定を登録解除する
UnregisterSettings();
}
}
virtual bool SupportsDynamicReloading() override
{
// DynamicReloadingはON
return true;
}
private:
// 設定を保存する
bool HandleSettingsSaved()
{
UMyGameSettings* Settings = GetMutableDefault<UMyGameSettings>();
bool ResaveSettings = false;
if (ResaveSettings)
{
Settings->SaveConfig();
}
return true;
}
// 設定を登録する
void RegisterSettings()
{
#if WITH_EDITOR
// Settingsモジュールを取得
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
// 設定用のカテゴリーを追加する
ISettingsSectionPtr SettingsSection = SettingsModule->RegisterSettings("Project", "CustomSettings", "General",
LOCTEXT("RuntimeGeneralSettingsName", "General"),
LOCTEXT("RuntimeGeneralSettingsDescription", "MyConfiguration"),
GetMutableDefault<UMyGameSettings>());
if (SettingsSection.IsValid())
{
// 更新時の自動保存処理を登録
SettingsSection->OnModified().BindRaw(this, &FCustomSettingsModule::HandleSettingsSaved);
}
}
#endif
}
// 設定を登録解除する
void UnregisterSettings()
{
#if WITH_EDITOR
// Settingsモジュールを取得
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
// カテゴリーごと削除する
SettingsModule->UnregisterSettings("Project", "CustomSettings", "General");
}
#endif
}
};
#undef LOCTEXT_NAMESPACE
[ProjectName].cpp
の方も書き換えます(自分のProject名で置き換えてね)
FDefaultGameModuleImpl
の部分が、先程書いたクラス名になっていればOKです
#include "[ProjectName].h"
#include "Modules/ModuleManager.h"
//IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, [ProjectName], "[ProjectName]");
IMPLEMENT_PRIMARY_GAME_MODULE(FCustomSettingsModule, [ProjectName], "[ProjectName]");
ここまで出来たらコンパイルしましょう
コンパイルが完了したら、ProjectSettingsをチェックしてみてください
ProjectSettingsに項目が追加されているのがわかります
おまけ
せっかくなのでBlueprintで使えるようにしてみましょう
BlueprintFunctionLibraryを追加します
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MyGameSettings.h"
#include "MySettingsFunctionLibrary.generated.h"
/**
*
*/
UCLASS()
class CPP424_API UMySettingsFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
// デフォルトActorのクラス名を取得する
UFUNCTION(BlueprintPure, Category = "MyGameSettings")
static TSubclassOf<class AActor> GetDefaultSpawnActorClass()
{
// 設定をロードする
UMyGameSettings* Settings = GetMutableDefault<UMyGameSettings>();
return Settings->DefaultSpawnActor;
}
};
こうしておけばProjectSettingsで設定した値が、Blueprint内で使えますね
注意点
SettingsモジュールはEditor用のモジュールであり、Package時には参照できません
なのでSettingsモジュールを使っている部分は必ず#if WITH_EDITOR ~ #endif
で囲んでおき、Packaging時に参照されないようにしておきましょう
この点を知らないと、下記のようなエラーが出てくるため、大変混乱することになります
fatal error C1083: Cannot open include file: 'ISettingsModule.h': No such file or directory
UnrealEngineのC++に慣れてる人はこれでだいたい察せますが、慣れてない人は「なんで?デバッグでは動いてたじゃん」と叫ぶことになるでしょう
参考資料