UE5.0 中的设置面板有两种,一个是Editor Preferences,另一个是Project Settings。
下面将用C++在这两个面板内添加自定义的设定
方法1:继承UObject,手动注册
新建一个C++工程,名为MyDemo。
编写一个设置面板类UMyCustomSetting,成员变量作为设置面板的设置内容。
MyCustomSetting.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "MyCustomSetting.generated.h"
UCLASS()
class MYDEMO_API UMyCustomSetting : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, Category = Setting1)
bool UseCustomSetting;
UPROPERTY(EditAnywhere, Category = Setting2, meta=(UIMin=1,EditConditionHides=true,EditCondition="UseCustomSetting==true"))
float Health = 100;
UPROPERTY(EditAnywhere, Category = Setting2, meta=(UIMin=30,UIMax=300,EditConditionHides=true,EditCondition="UseCustomSetting==true"))
float Ammo = 240;
};
然后在模块启动时注册UMyCustomSetting类,所以我们先新建一个FMyDemoGameModule模块,在模块启动时注册Setting类,模块关闭时反注册。
MyDemo.h
#pragma once
#include "CoreMinimal.h"
class FMyDemoGameModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
virtual bool IsGameModule() const override;
};
MyDemo.cpp
#include "MyDemo.h"
#include "ISettingsModule.h"
#include "MyCustomSetting.h"
#include "Modules/ModuleManager.h"
void FMyDemoGameModule::StartupModule()
{
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (SettingsModule != nullptr)
{
SettingsModule->RegisterSettings("Editor", "MyDemo", "My Custom Setting",
FText::FromString(TEXT("我的自定义设置")),
FText::FromString(TEXT("这是自定义设置的描述")),
GetMutableDefault<UMyCustomSetting>());
}
}
void FMyDemoGameModule::ShutdownModule()
{
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (SettingsModule != nullptr)
{
SettingsModule->UnregisterSettings("Editor", "MyDemo", "My Custom Setting");
}
}
bool FMyDemoGameModule::IsGameModule() const
{
return true;
}
IMPLEMENT_PRIMARY_GAME_MODULE(FMyDemoGameModule, MyDemo, "MyDemo");
注册设置面板调用的是ISettingModule的RegisterSettings函数
其中ContainerName可以指定“Project”或“Editor”,分别对应Project Settings和Editor Preferences。
其他参数对应的内容如下图:
方法2:继承UDeveloperSettings类,引擎自动注册
MyCustomSetting2.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DeveloperSettings.h"
#include "MyCustomSetting2.generated.h"
UCLASS()
class MYDEMO_API UMyCustomSetting2 : public UDeveloperSettings
{
GENERATED_BODY()
public:
// 等效方法1的ContainerName参数
virtual FName GetContainerName() const override
{
return "Project";
}
// 等效方法1的CategoryName参数
virtual FName GetCategoryName() const override
{
return "MyDemo";
}
// 等效方法1的SectionName参数
virtual FName GetSectionName() const override
{
return "My Custom Setting";
}
// 等效方法1的DisplayName参数
virtual FText GetSectionText() const override
{
return FText::FromString(TEXT("我的自定义设置"));
}
// 等效方法1的Description参数
virtual FText GetSectionDescription() const override
{
return FText::FromString(TEXT("这是自定义设置的描述"));
}
UPROPERTY(EditAnywhere, Category = Setting1)
bool UseCustomSetting;
UPROPERTY(EditAnywhere, Category = Setting2, meta=(UIMin=1,EditConditionHides=true,EditCondition="UseCustomSetting==true"))
float Health = 100;
UPROPERTY(EditAnywhere, Category = Setting2, meta=(UIMin=30,UIMax=300,EditConditionHides=true,EditCondition="UseCustomSetting==true"))
float Ammo = 240;
};
第二种方法不用考虑何时注册,而且提供了属性更改时触发的多播代理FOnSettingsChanged
最终效果如上图
保存设置面板的内容
上一小节中,我们实现了自定义的面板,但是有个问题,修改后的值并没有保存,每次打开编辑器都会恢复默认的值。
以UMyCustomSetting类为例
UCLASS(Config=MyDemo, DefaultConfig)
class MYDEMO_API UMyCustomSetting : public UObject
{
...
};
1. 在UCLASS指定类说明符:Config=MyDemo, DefaultConfig
这些说明符的含义可以在官方文档内可以查到
Config=ConfigName :指示此类可在*.ini文件中存储数据,`ConfigName`为文件名称。常见的`ConfigName`值是"Engine"、"Editor"、"Input"和"Game"。
DefaultConfig:仅将类配置保存到Default[ConfigName].ini,不保存到本地 (Saved文件夹)。
此外,还有备选说明符:
PerObjectConfig:为每个实例保存配置文件。
ConfigDoNotCheckDefaults:序列化类的时候不会检查默认配置内的值
2. 为UPROPERTY添加说明符
UPROPERTY(Config, EditAnywhere, Category = Setting1)
bool UseCustomSetting;
Config:有此说明符的Property会被保存到配置文件内对应的Section中。
GlobalConfig:跟Config差不多,但是子类的该Property会从基类中读取值。
项目文件夹Config中可以找到保存的ini文件
访问设置类内的参数
使用CDO来访问设置参数
GetDefault<T>() 可以获取const T*
GetMutableDefault<T>()可以获取T*,可以用来修改Setting类内的数值
// 访问使用GetDefault
const UMyCustomSetting* MyCustomSetting = GetDefault<UMyCustomSetting>();
if (MyCustomSetting)
{
FString TrueOrFalse = MyCustomSetting->UseCustomSetting ? L"True" : L"False";
UE_LOG(LogTemp, Display, TEXT("UseCustomSetting = %s"), *TrueOrFalse);
if (MyCustomSetting->UseCustomSetting)
{
UE_LOG(LogTemp, Display, TEXT("Health=%d, Ammo=%d"), MyCustomSetting->Health,MyCustomSetting->Ammo);
}
}
// 修改使用GetMutableDefault
UMyCustomSetting2* MyCustomSetting2 = GetMutableDefault<UMyCustomSetting2>();
if (MyCustomSetting2)
{
MyCustomSetting2->UseCustomSetting = true;
MyCustomSetting2->Health = 150;
MyCustomSetting2->Ammo = 300;
}