前言
我们在项目开发的过程中,经常需要在项目设置里面添加一些参数,本文介绍如何添加这些参数
另外介绍一些特殊的资源类参数的添加和使用
先上图
添加自定义项目设置 一般情况下,我们需要创建一个插件来添加这类属性,我们创建一个蓝图函数库模板的插件
然后创建一个UObject类来添加属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 UCLASS (config = ExtensionSetting,defaultconfig)class GAMESETTINGEXTENSION_API USettingObj : public UObject{ GENERATED_BODY () public : UPROPERTY (config, BlueprintReadOnly, EditAnywhere) FSoftClassPath SoftClassPath; UPROPERTY (config, BlueprintReadOnly, EditAnywhere) FSoftObjectPath SoftObjectPath; UPROPERTY (config, BlueprintReadOnly, EditAnywhere) TSoftObjectPtr<AActor> SoftObjectPtr; UPROPERTY (config, BlueprintReadOnly, EditAnywhere) TSoftClassPtr<AActor> SoftClassPtr; };
configdonotcheckdefaults 与 defaultconfig
defaultconfig :配置会写入到引擎默认配置里, 路径一般是./Config
内而不是./Save/*/Config
内.另外打包出来后运行以后会自动生成配置文件信息,但是无法再手动修改ini
文件; 可以运行时修改但是会保存到./Save/*/Windows/Config
内对应名称的ini
内
configdonotcheckdefaults :会写入到./Save
内, 运行运行时的修改;打包以后不会自动生成ini
文件, 可以手动复制到对应目录
**CLASS(config=FileName)**:表示这个类默认条件下将配置信息保存到哪个配置文件,config后面的文件名可以是任意字符串。
**UPROPERTY(globalconfig)**:不指定Section的情况下,标记config的这个属性在保存到配置文件里面的时候会保存在基类对应的Section部分。同理,加载的时候也会从基类对应的Section下加载。
注意要在UPROPERTY
后加config
关键字
一般的值类型变量都都可以配置,如FString
,FRotator
,TSubclassOf
,但是不能添加继承于UObject
的类,可以用FSlot***
代替
然后我们需要将此类注册到游戏设置里面,一般是在模块启动的时候添加,看下面代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void FGameSettingExtensionModule::RegisterSetting () { if (ISettingsModule* SettingModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings" )) { SettingModule->RegisterSettings ("Project" , "Game" , "ExtensionSetting" , LOCTEXT ("RuntimeSettingsName" , "GameSetting" ), LOCTEXT ("RuntimeSettingsDescription" , "Configure my GameSetting" ), GetMutableDefault<USettingObj>() ); } } void FGameSettingExtensionModule::UnregisterSetting () { if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings" )) { SettingsModule->UnregisterSettings ("Project" , "Game" , "ExtensionSetting" ); } }
上面代码在模块启动和注销的时候分别调用
“Game”:表示分类,对应的就是项目设置的Game标签
“ExtensionSetting”:配置时的分类名称
“Configure my GameSetting”:上图中的文字描述
使用自定义设置 因为我们本身就是一个蓝图函数库插件,我们直接在函数库类里面添加新的方法,如果不是此类插件,自己新建一个蓝图函数库类
需要注意的问题,编辑器类型的插件不能使用蓝图函数库
1 2 3 4 5 6 7 8 9 10 UFUNCTION (BlueprintCallable, BlueprintPure, Category = "GameSettingExtension" ) static UObject* GetObjBySoftPath (const FSoftObjectPath& softPath) ; UFUNCTION (BlueprintCallable, BlueprintPure, Category = "GameSettingExtension" ) static UObject* GetObjRefBySoftPtr (const TSoftObjectPtr<UObject>& softPathPtr) ; UFUNCTION (BlueprintCallable, BlueprintPure, Category = "GameSettingExtension" ) static UClass* GetClassBySoftPath (const FSoftClassPath& softPath) ; UFUNCTION (BlueprintCallable, BlueprintPure, Category = "GameSettingExtension" ) static UClass* GetClassByClassSoftPtr (const TSoftClassPtr<UObject>& softPathPtr) ;
我们申明4个变量对应的4个函数,因为例如FSoftObjectPath
类型的变量在蓝图里面不方便使用,所以需要我们用C++
封装一层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 UObject* UGameSettingExtensionBPLibrary::GetObjBySoftPath (const FSoftObjectPath& softPath) { UObject* obj = LoadObject<UObject>(NULL , *softPath.ToString ()); return obj; } UObject* UGameSettingExtensionBPLibrary::GetObjRefBySoftPtr (const TSoftObjectPtr<UObject>& softPathPtr) { TSoftObjectPtr<UObject> p = TSoftObjectPtr<UObject>(softPathPtr); return p.Get (); } UClass* UGameSettingExtensionBPLibrary::GetClassBySoftPath (const FSoftClassPath& softPath) { UClass* c = LoadClass<UObject>(NULL , *softPath.ToString ()); return c; } UClass* UGameSettingExtensionBPLibrary::GetClassByClassSoftPtr (const TSoftClassPtr<UObject>& softPathPtr) { TSoftClassPtr<UObject> p = TSoftClassPtr<UObject>(softPathPtr); return p.Get (); }
这样我们就实现了蓝图里面调用项目设置内的属性了
读写 只要继承自UObject
类就有两个方法SaveConfig()
和LoadConfig()
1 void SaveConfig ( uint64 Flags=CPF_Config, const TCHAR* Filename=NULL , FConfigCacheIni* Config=GConfig, bool bAllowCopyToDefaultObject=true ) ;
第一个参数Flags
: 一般不用改变, 可以设置为CPF_GlobalConfig
标记为全局
第二个参数Filename
:保存的文件, 如果不填写则使用前面UCLASS
定义的路径
第三个参数保持默认即可
1 void LoadConfig ( UClass* ConfigClass=NULL , const TCHAR* Filename=NULL , uint32 PropagationFlags=UE4::LCPF_None, class FProperty* PropertyToLoad=NULL ) ;
LoadConfig()
的功能是从配置文件里面读取特定的属性值并赋给指定类的对应属性。第一个参数指定了要把值赋给哪个类的属性,第二个参数表示到哪个配置文件找对应的配置信息,第三个参数表示是哪种标记(Config还是GlobalConfig),第四个参数表示指定要赋值的属性。
如果不指定第4个参数,就会读取配置并给所有标记UProperty(Config)
的属性赋值。
可以在注册的位置就绑定Setting
类的修改, 然后实时保存到ini
文件内
1 2 3 4 5 6 7 8 9 10 11 if (ISettingsModule* SettingModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings" )) { ISettingsSectionPtr SettingsSection = SettingModule->RegisterSettings ("Project" , "Game" , "SuperRoad" , LOCTEXT ("RuntimeSettingsName" , "SuperRoad" ), LOCTEXT ("RuntimeSettingsDescription" , "Configure my GameSetting" ), GetMutableDefault<USRDefaultSettings>()); if (SettingsSection.IsValid ()) { SettingsSection->OnModified ().BindRaw (this , &FSuperRoadModule::HandleSettingsSaved); } }
1 2 3 4 5 6 7 8 9 10 11 bool FSuperRoadModule::HandleSettingsSaved () { USRDefaultSettings* s = GetMutableDefault<USRDefaultSettings>(); if (s) { s->SaveConfig (); SRLOG (TEXT ("Save Settings" )); return true ; } return false ; }
当然, 运行时直接拿到对象修改变量是无法调用到这里的, 需要自己调用或者封装Save
函数
还有一个方式也可以读写变量, 使用GConfig
GConfig
可以理解为是一个全局的变量(类型是FConfigIni
), 所有配置文件都可以通过此来获取和设置变量
以下是Wiki的案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 void AVictoryController::VictoryConfigGetTests () { if (!GConfig) return ; FString ValueReceived; GConfig->GetString ( TEXT ("/Script/Engine.WorldInfo" ), TEXT ("GlobalDefaultGameType" ), ValueReceived, GGameIni ); ClientMessage ("GlobalDefaultGameType" ); ClientMessage (ValueReceived); int32 IntValueReceived = 0 ; GConfig->GetInt ( TEXT ("Core.System" ), TEXT ("MaxObjectsNotConsideredByGC" ), IntValueReceived, GEngineIni ); ClientMessage ("MaxObjectsNotConsideredByGC" ); ClientMessage (FString::FromInt (IntValueReceived)); float floatValueReceived = 0 ; GConfig->GetFloat ( TEXT ("/Script/Engine.Engine" ), TEXT ("NearClipPlane" ), floatValueReceived, GEngineIni ); ClientMessage ("NearClipPlane" ); ClientMessage (FString::SanitizeFloat (floatValueReceived)); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 void AVictoryController::VictoryConfigSetTests () { if (!GConfig) return ; FString VictorySection = "Victory.Core" ; GConfig->SetString ( *VictorySection, TEXT ("RootDir" ), TEXT ("E:\UE4\IsAwesome" ), GGameIni ); GConfig->SetColor ( *VictorySection, TEXT ("Red" ), FColor (255 ,0 ,0 ,255 ), GGameIni ); GConfig->SetVector ( *VictorySection, TEXT ("PlayerStartLocation" ), FVector (0 ,0 ,512 ), GGameIni ); GConfig->SetRotator ( *VictorySection, TEXT ("SunRotation" ), FRotator (-90 ,0 ,0 ), GGameIni ); GConfig->Flush (false ,GGameIni); }
注意: 写入操作以后需要调用GConfig->Flush(false,GGameIni);
否则配置文件不会修改
其他可配置变量 FSoftObjectPath 软对象路径,可以直接转换成FString
然后从路径得到具体的类型
1 UObject* obj = LoadObject<UObject>(NULL , *softPath.ToString ());
用meta参数类刷选特定类
1 meta = (AllowedClasses ="Material,StaticMesh" )
FSoftClassPath 同上,得到一个蓝图类的UClass
1 UClass* c = LoadClass<UObject>(NULL , *softPath.ToString ());
可以用meta参数来刷选特定类,与FSoftObjectPath
的meta参数不一样
1 meta = (MetaClass = "MyActor" )
TSoftObjectPtr TSoftObjectPtr是封装了FSoftObjectPtr的模板,同样是用于“在给予文件路径下检测一个资源是否已经加载进了内存,获取资源对应的对象指针”,类似上面的一种写法, 直接帮我们省掉了“Cast”转为对象的过程
1 2 TSoftObjectPtr<UObject> p = TSoftObjectPtr<UObject>(softPathPtr); return p.Get ();
实测发现该变量指向的是场景中的具体对象,与FSoftObjectPath
指向不同
TSoftClassPtr 跟TSoftObjectPtr类似,只不过TSoftClassPtr是仅仅用于UClass*
1 2 TSoftClassPtr<UObject> p = TSoftClassPtr<UObject>(softPathPtr); return p.Get ();
参考资料 WiKi:Legacy/Config Files, Read & Write to Config Files
Wiki:Legacy/CustomSettings
CSDN:UE4 Config配置文件详解