引言

在日常的开发中会遇到很多使用C++来加载资源的情况,例如我们要引用Content下的蓝图类和非蓝图类,那么在UE4中提供了很多机制来引用这些资源。从网上查到的很多资料来看,很多游戏开发者将这种机制称之为“静态加载”和“动态加载”,但是从官方文档上来看,我并没有搜到静态加载相关的词语,官方将这种机制称之为“硬性引用(HardRefernences)”和“软性应用(SoftReferences)”。在这篇文章中我会把网上的资料和官方资料整理一下,也方便以后查阅。

静态加载-硬性引用 我这里理解的是静态加载和硬性引用一个意思,对应的动态加载和软性引用一个意思。硬性应用由两种场景的情况。 (1)直接属性引用:这是最常见的资源引用情况,通过宏UPROPERTY暴露给蓝图,这样可以允许设计人员在编辑器中指定相关资源。示例代码如下: /** construction start sound stinger */

UPROPERTY(EditDefaultsOnly, Category=Building)

USoundCue* ConstructionStartStinger;

(2)构造时引用:在构造函数引用确切的资源,这里是使用特殊的类ConstructorHelpers完成的,这个类中有两个对应的方法:FObjectFinder()和FClassFinder(),它们分别加载的是非蓝图资产(动画、贴图、模型、音效等)和蓝图类(角色蓝图、Widget控件)资产。示例代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
static ConstructorHelpers::FClassFinder<AChatOnline_WFYCharacter> PlayerPawnBPClass(TEXT("/Game/ChatOnline/WFY_Blueprint/Core/WFY_Character"));
static ConstructorHelpers::FClassFinder<AHUD> PlayerHUDBPClass(TEXT("/Game/ChatOnline/WFY_Blueprint/Core/ChatOnline_WFYHUD_BP"));

//DefaultPawnClass = AChatOnline_WFYCharacter::StaticClass();
if (PlayerPawnBPClass.Class!=NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
if (PlayerHUDBPClass.Class!=NULL)
{
HUDClass = PlayerHUDBPClass.Class;
}

class UTexture2D* BarFillTexture;
static ConstructorHelpers::FObjectFinder<UTexture2D> BarFillObj(TEXT("/Game/UI/HUD/BarFill"));
BarFillTexture = BarFillObj.Object;

(了解更多:在以上构造函数中,ConstructorHelpers 类将尝试在内存中查找该资源,如果找不到,则进行加载。请注意,使用资源的完整路径来指定要加载的内容。如果该资源不存在或者由于出错而无法加载,那么该属性将设置为 nullptr。发生这种情况时,尝试访问纹理的代码将崩溃。最好进行声明,指出资源已正确加载(如果后续代码假设引用有效)。 UPROPERTY 的声明与前面的硬性引用示例相同。它们的工作方式相同,只不过是最初的设置方式有所差别。有关硬性引用的一个注意事项是,当对象加载并实例化时,还将加载以硬性方式引用的资源。您必须仔细地进行考虑,否则内存使用量会因为同时加载许多资源而迅速增加。如果您希望推迟该加载或确定要在运行时加载的内容,那么下列各节可以帮助您完成这些任务。)

动态加载-软性引用 动态加载最常用的两个模板化方法是LoadObject<>()和LoadClass<>()。同样的前者加载非蓝图类资产后者加载蓝图类资产。需要注意的是使用LoadClass时,路径名必须带_C后缀,LoadObject不需要带后缀。示例代码如下: //加载Content目录下的资源文件 UTexture2D* SpeackCheck; UTexture2D* MicCheck; //方法一: SpeackCheck = LoadObject(nullptr, TEXT("/Game/ChatOnline/WFY_Textture/Icon/Speaker_Check"));

//方法二 FSoftObjectPath softObjectPath(TEXT("/Game/ChatOnline/WFY_Textture/Icon/Mic_check"));

1
2
3
4
5
6
7
8
UObject* object = softObjectPath.TryLoad();
MicCheck = Cast<UTexture2D>(object)
//LoadClass<>()
TSubclassOf<UUI_TopTitle> TopTitle = LoadClass<UUI_TopTitle>(nullptr, TEXT("/Game/ChatOnline/WFY_Widget/Common/CharacterTopTitle.CharacterTopTitle_C"));

pTopTitle = CreateWidget<UUI_TopTitle>(GetWorld(), TopTitlef.Class);

Node
1
ConstructorHelpers::FClassFinder<>()ConstructorHelpers::FObjectFinder()不能在构造函数之外使用,否则会报错如下“FObjectFinders can't be used outside of constructors to find %s”,其他地方可以使用LoadClass()LoadObject()

在实际开发过程中遇到的一些需要注意的点,在继承自“UUserWidget”的类中,不能在函数“NativeConstruct()”中调用ConstructorHelpers::FObjectFinder()和FClassFinder(),否则也会报同样的错误。正确示例代码:

UCLASS()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class UUI_TopTitle : public UUserWidget
{
GENERATED_BODY()

public:

virtual void NativeConstruct();

virtual void NativeDestruct();

virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime);


void UUI_TopTitle::NativeConstruct()
{
Super::NativeConstruct();

Speaking = LoadObject<UTexture2D>(nullptr, TEXT("/Game/ChatOnline/WFY_Textture/Icon/Speaker_Check"));
NoSpeaker = LoadObject<UTexture2D>(nullptr, TEXT("/Game/ChatOnline/WFY_Textture/Icon/Speaker_Uncheck"));

参考链接: https://docs.unrealengine.com/4.27/zh-CN/ProgrammingAndScripting/ProgrammingWithCPP/Assets/ReferencingAssets/

https://blog.csdn.net/yb0022/article/details/103104215

知乎 https://zhuanlan.zhihu.com/p/266859719

https://www.pianshen.com/article/3032128253/