同步加载

同步加载会造成进程阻塞。

FObjectFinder / FClassFinder

在构造函数加载

LoadObject

  • 一般用来加载资源对象
UMaterial* M_Cube = LoadObject<UMaterial>(nullptr, TEXT("Material'/Game/Geometry/Meshes/CubeMaterial.CubeMaterial'"));
if (M_Cube)
{
UE_LOG(LogTemp, Warning, TEXT("Material name:%s"), *M_Cube->GetName());
}
  • 早期版本 StaticLoadObject() ,本处只作为记录,推荐使用 LoadObject
soundCue = Cast<USoundCue>(StaticLoadObject(USoundCue::StaticClass(), nullptr, TEXT("SoundCue'/Game/Demo_Drone/Sound/explore_Cue.explore_Cue'")));
UGameplayStatics::PlaySoundAtLocation(this, soundCue,SweepResult.Location);

LoadClass

  • 一般用来加载蓝图类, UClass*
  • 蓝图类的路径末尾加上_C
UClass* pClass = LoadClass<AActor>(nullptr, TEXT("Blueprint'/Game/CPPFunction/Load/BP_LoadActor.BP_LoadActor_C'"));
if (pClass)
{
UE_LOG(LogTemp, Warning, TEXT("pClass name:%s"), *pClass->GetName());
} TSubclassOf<AActor> BPClass = LoadClass<AActor>(nullptr, TEXT("Blueprint'/Game/CPPFunction/Load/BP_MyActor'"));
if (BPClass)
{
UE_LOG(LogTemp, Warning, TEXT("BPClass name:%s"), *BPClass->GetName());
}

TryLoad

  • 配合 FSoftObjectPath 使用
  • TryLoad 中调用 LoadObject,加载时需要调用Cast转换一下
FSoftObjectPath SoftObjectPaths_Mesh = FSoftObjectPath(TEXT("StaticMesh'/Game/CPPFunction/Load/StaticMesh.StaticMesh'"));
UStaticMesh* Mesh1 = Cast<UStaticMesh>(SoftObjectPaths_Mesh.TryLoad());
if (Mesh1)
{
UE_LOG(LogTemp, Warning, TEXT("Mesh1 name:%s"), *Mesh1->GetName());
}

TryLoadClass

  • 搭配 FSoftClassPath 使用
  • TryLoadClass 中调用了 LoadClass
FSoftClassPath SoftClassPath_Actor = FSoftClassPath(TEXT("Blueprint'/Game/CPPFunction/Load/BP_MyActor_SoftRef.BP_MyActor_SoftRef_C'"));
UClass* pClass_Actor = SoftClassPath_Actor.TryLoadClass<AActor>();
if (pClass_Actor)
{
UE_LOG(LogTemp, Warning, TEXT("pClass_Actor name:%s"), *pClass_Actor->GetName());
}

FStreamableManager::LoadSynchronous

  • FStreamableManager::内部调用 RequestSyncLoad
  • 参数中返回一个FStreamableHandle类型的指针

可加载非蓝图资源类

  • 配合FStreamableManager、FSoftObjectPath 使用
  • 配合FStreamableManager、TSoftObjectPtr使用
// 配合 FSoftObjectPath 使用 方法一
FSoftObjectPath SoftObjectPaths_Mesh1 = FSoftObjectPath(TEXT("StaticMesh'/Game/CPPFunction/Load/StaticMesh.StaticMesh'"));
UStaticMesh* StaticMesh1 = UAssetManager::GetStreamableManager().LoadSynchronous<UStaticMesh>(SoftObjectPaths_Mesh1);
if (StaticMesh1)
{
UE_LOG(LogTemp, Warning, TEXT("Mesh1 name:%s"), *StaticMesh1->GetName());
} // 配合 FSoftObjectPath 使用 方法二
FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
FSoftObjectPath SoftObjectPaths_Mesh2 = FSoftObjectPath(TEXT("StaticMesh'/Game/CPPFunction/Load/StaticMesh_Soft.StaticMesh_Soft'"));
UStaticMesh* StaticMesh2 = streamableManager.LoadSynchronous<UStaticMesh>(SoftObjectPaths_Mesh2);
if (StaticMesh2)
{
UE_LOG(LogTemp, Warning, TEXT("Mesh2 name:%s"), *StaticMesh2->GetName());
} // 配合 TSoftObjectPtr<T> 使用
FSoftObjectPath SoftObjectPaths_Mesh3 = FSoftObjectPath(TEXT("StaticMesh'/Game/CPPFunction/Load/StaticMesh_Soft2.StaticMesh_Soft2'"));
TSoftObjectPtr<UStaticMesh> SoftObjectPtr_Mesh = TSoftObjectPtr<UStaticMesh>(SoftObjectPaths_Mesh3);
UStaticMesh* StaticMesh3 = streamableManager.LoadSynchronous(SoftObjectPtr_Mesh);//保持良好习惯<UStaticMesh>
if (StaticMesh3)
{
UE_LOG(LogTemp, Warning, TEXT("Mesh3 name:%s"), *StaticMesh3->GetName());
}

也可加载蓝图类为 UClass*

  • 配合FStreamableManager、TSoftObjectPtr使用
  • 配合FStreamableManager、TSoftClassPtr使用
FSoftObjectPath SoftObjectPaths_Actor1 = FSoftObjectPath(TEXT("Blueprint'/Game/CPPFunction/Load/BP_MyActor.BP_MyActor_C'"));
UClass* BPClass1 = UAssetManager::GetStreamableManager().LoadSynchronous<UClass>(SoftObjectPaths_Actor1);
if (BPClass1)
{
UE_LOG(LogTemp, Warning, TEXT("BPClass1 name:%s"), *BPClass1->GetName());
} // 配合 FSoftObjectPath 使用 方法二
FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
FSoftObjectPath SoftObjectPaths_Actor2 = FSoftObjectPath(TEXT("Blueprint'/Game/CPPFunction/Load/BP_MyActor_SoftRef.BP_MyActor_SoftRef_C'"));
UClass* BPClass2 = streamableManager.LoadSynchronous<UClass>(SoftObjectPaths_Actor2);
if (BPClass2)
{
UE_LOG(LogTemp, Warning, TEXT("BPClass2 name:%s"), *BPClass2->GetName());
} // 配合 TSoftObjectPtr<T> 使用
FSoftObjectPath SoftObjectPaths_Actor3 = FSoftObjectPath(TEXT("Blueprint'/Game/CPPFunction/Load/BP_MyActor_SoftRef2.BP_MyActor_SoftRef2_C'"));
TSoftObjectPtr<UClass> SoftObjectPtr_Actor = TSoftObjectPtr<UClass>(SoftObjectPaths_Actor3);
UClass* BPClass3 = streamableManager.LoadSynchronous(SoftObjectPtr_Actor); //保持良好习惯可添加<UClass>
if (BPClass3)
{
UE_LOG(LogTemp, Warning, TEXT("BPClass3 name:%s"), *BPClass3->GetName());
}

FStreamableManager::RequestSyncLoad

  • 配合 FStreamableManager、FSoftObjectPath 使用
  • 返回一个FStreamableHandle类型的指针
  • TSharedPtr 通过 GetLoadedAsset() 获取单个资源
  • TSharedPtr 通过 GetLoadedAssets() 获取多个资源
// 获取单个资源 方法一
FSoftObjectPath SoftObjectPaths_Mesh1 = FSoftObjectPath(TEXT("StaticMesh'/Game/CPPFunction/Load/StaticMesh.StaticMesh'"));
TSharedPtr<FStreamableHandle> Handle1 = UAssetManager::GetStreamableManager().RequestSyncLoad(SoftObjectPaths_Mesh1);
if (Handle1.IsValid())
{
UStaticMesh* StaticMesh1 = Cast<UStaticMesh>(Handle1->GetLoadedAsset());
UE_LOG(LogTemp, Warning, TEXT("Mesh1 name:%s"), *StaticMesh1->GetName());
} // 获取单个资源 方法二
FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
FSoftObjectPath SoftObjectPaths_Mesh2 = FSoftObjectPath(TEXT("StaticMesh'/Game/CPPFunction/Load/StaticMesh_Soft.StaticMesh_Soft'"));
TSharedPtr<FStreamableHandle> Handle2 = streamableManager.RequestSyncLoad(SoftObjectPaths_Mesh2);
if (Handle2.IsValid())
{
UStaticMesh* StaticMesh2 = Cast<UStaticMesh>(Handle2->GetLoadedAsset());
UE_LOG(LogTemp, Warning, TEXT("Mesh1 name:%s"), *StaticMesh2->GetName());
} // 获取多个资源
TArray<FSoftObjectPath> SoftObjectPaths;
SoftObjectPaths.Add(SoftObjectPaths_Mesh1);
SoftObjectPaths.Add(SoftObjectPaths_Mesh2);
TSharedPtr<FStreamableHandle> Handle3 = streamableManager.RequestSyncLoad(SoftObjectPaths);
{
TArray<UObject*> Objects;
Handle3->GetLoadedAssets(Objects);
for (UObject* item : Objects)
{
UStaticMesh* StaticMesh3 = Cast<UStaticMesh>(item);
UE_LOG(LogTemp, Warning, TEXT("GetLoadedAssets(), item name:%s"), *StaticMesh3->GetName());
}
}

异步加载

  • 为了避免阻塞主线程,可以使用异步加载的方式来加载资源
  • 异步加载完成后,可以设置回调函数
  • 创建 FStreamableManager,建议将它放在某类全局游戏单件对象中,如使用GameSingletonClassNameDefaultEngine.ini 中指定的对象

FStreamableManager::RequestAsyncLoad

  • 返回一个 FStreamableHandle 类型的指针

异步加载非蓝图类资源 FSoftObjectPath

  • 单文件加载

    UPROPERTY(EditAnywhere, Category = "SoftObjectPath", meta = (AllowedClasses = "StaticMesh"))
    FSoftObjectPath SingeleObject; UFUNCTION()
    void OnSingleAssetLoadFinshed();
    // 函数内部分语句
    FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
    FStreamableDelegate streamableDelegate = FStreamableDelegate::CreateUObject(this, &ALoadActor::OnSingleAssetLoadFinshed);
    streamableManager.RequestAsyncLoad(SingeleObject, streamableDelegate); // 要回调的函数
    void ALoadActor::OnSingleAssetLoadFinshed()
    {
    FSoftObjectPtr SoftObjPtr = FSoftObjectPtr(SingeleObject);
    UStaticMesh* mesh = Cast<UStaticMesh>(SoftObjPtr.Get());
    if (mesh)
    {
    UE_LOG(LogTemp, Warning, TEXT("mesh name:%s"), *mesh->GetName());
    }
    }

  • 多文件加载

    • 方法一 配合 FSoftObjectPtr

      • FSoftObjectPtr是一个结构体,是一种指向UObject的弱指针。无法在蓝图中使用
      • TSoftObjectPtr是一个模板类,是通用FSoftObjectPtr的模块化包装器
      UPROPERTY(EditAnywhere, Category="SoftObjectPath", meta = (AllowedClasses = "StaticMesh"))
      TArray<FSoftObjectPath> ObjectList1; UFUNCTION()
      void OnMultiAssetsLoadFinshed1();
      // 函数内部分语句
      FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
      FStreamableDelegate streamableDelegate = FStreamableDelegate::CreateUObject(this, &ALoadActor::OnMultiAssetsLoadFinshed1);
      streamableManager.RequestAsyncLoad(ObjectList1, streamableDelegate); // 要回调的函数
      void ALoadActor::OnMultiAssetsLoadFinshed1()
      {
      for (auto AssetItem : ObjectList1)
      {
      FSoftObjectPtr SoftObjPtr = FSoftObjectPtr(AssetItem); //此处也可用 TSoftObjectPtr<T>
      UStaticMesh* mesh = Cast<UStaticMesh>(SoftObjPtr.Get());
      if (mesh)
      {
      UE_LOG(LogTemp, Warning, TEXT("mesh name:%s"), *mesh->GetName());
      }
      }
      }

    • 方法二 配合TSoftObjectPtr<T>

      UPROPERTY(EditAnywhere, Category = "SoftObjectPath")
      TArray<TSoftObjectPtr<UTexture2D>> ObjectList2; UFUNCTION()
      void OnMultiAssetsLoadFinshed2();
      // 函数内部分语句
      FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
      FStreamableDelegate streamableDelegate;
      streamableDelegate.BindUObject(this, &ALoadActor::OnMultiAssetsLoadFinshed2); TArray<FSoftObjectPath> SoftPathList;
      for (int32 i=0; i<ObjectList2.Num(); i++)
      {
      SoftPathList.Add(ObjectList2[i].ToSoftObjectPath());
      }
      streamableManager.RequestAsyncLoad(SoftPathList, streamableDelegate); // 要回调的函数
      void ALoadActor::OnMultiAssetsLoadFinshed2()
      {
      for (auto AssetItem : ObjectList2)
      {
      UTexture2D* ItemTex = AssetItem.Get();
      if (ItemTex)
      {
      UE_LOG(LogTemp, Warning, TEXT("Texture2D name:%s"), *ItemTex->GetName());
      }
      }
      }

异步加载蓝图类

  • 单文件加载 FSoftClassPath 、TSoftClassPtr

    • 测试 TArray<FSoftClassPath> 加载多个蓝图类编译不通过
    UPROPERTY(EditAnywhere, Category = "SoftClassPath", meta = (MetaClass = "Actor"))
    FSoftClassPath SingleClassPath; UFUNCTION()
    void OnSingleClassLoadFinshed();
    // 函数内部分语句
    FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
    FStreamableDelegate streamableDelegate = FStreamableDelegate::CreateUObject(this, &ALoadActor::OnSingleClassLoadFinshed);
    streamableManager.RequestAsyncLoad(SingleClassPath, streamableDelegate); // 函数内部分语句
    void ALoadActor::OnSingleClassLoadFinshed()
    {
    TSoftClassPtr<AActor> ItemPtr = TSoftClassPtr<AActor>(SingleClassPath);
    UClass* ItemClass = ItemPtr.Get();
    if (ItemClass)
    {
    UE_LOG(LogTemp, Warning, TEXT("Actor name:%s"), *ItemClass->GetName());
    }
    }

卸载资源

自动回收

  • 当对象失去饮用后会被自动释放。
  • 在异步回调结束后,对象会被标记可回收,此时使用 ForceGC 可销毁对象

手动回收

使用 FStreamableManager::Unload()

  • LoadSynchronous()、RequestSyncLoad()、RequestAsyncLoad() 默认bManageActiveHandle 参数为false,表示自动管理内存;当设为true,表示常驻内存直到手动释放
  • FStreamableManager::Unload()会Release掉和当前资源相关的所有FStreamableHandle
  • 编辑器模式下会一直常驻内存,打包版本中才会生效
FStreamableManager& streamableManager = UAssetManager::GetStreamableManager();
streamableManager.Unload(FSoftObjectPath(AssetPath)); //需要立即回收的话
GEngine->ForceGarbageCollection(true);
//GetWorld()->ForceGarbageCollection(true);

使用 FStreamableHandle::ReleaseHandle()

  • 异步加载时,如果资源还没加载完成就执行ReleaseHandle()(假设加载时bManageActiveHandle为true),比如在执行回调函数之前执行ReleaseHandle,那么当资源加载完成后(回调函数执行之后),会自动从内存中回收。不过该对象在回调函数中仍然有效,除非在回调函数内ForceGC。
  • 编辑器模式下会一直常驻内存,打包版本中才会生效
TSharedPtr<FStreamableHandle> Handle1  = UAssetManager::GetStreamableManager().RequestSyncLoad(SoftObjectPaths_Mesh1);
Handle1->ReleaseHandle();

使用 ConditionalBeginDestroy()

  • 编辑器模式下卸载后,对象从内存中销毁,无法再次Load,需要重启编辑器
UMaterial* M_Cube = LoadObject<UMaterial>(nullptr, TEXT("Material'/Game/Geometry/Meshes/CubeMaterial.CubeMaterial'"));
if (M_Cube)
{
M_Cube->ConditionalBeginDestroy();
M_Cube = nullptr;
GetWorld()->ForceGarbageCollection();
}

参考

【UE4 C++ 基础知识】<11>资源的同步加载与异步加载的更多相关文章

  1. 【UE4 C++ 基础知识】<10>资源的引用

    2种引用方式 硬引用(Hard Reference) 即对象 A 引用对象 B,并导致对象 B 在对象 A 加载时加载 硬引用过多会导致运行时很多暂时用不到的资源也被加载到内存中 大量资源会导致进程阻 ...

  2. 【UE4 C++ 基础知识】<3> 基本数据类型、字符串处理及转换

    基本数据类型 TCHAR TCHAR就是UE4通过对char和wchar_t的封装 char ANSI编码 wchar_t 宽字符的Unicode编码 使用 TEXT() 宏包裹作为字面值 TCHAR ...

  3. 【UE4 C++ 基础知识】<12> 多线程——FRunnable

    概述 UE4里,提供的多线程的方法: 继承 FRunnable 接口创建单个线程 创建 AsyncTask 调用线程池里面空闲的线程 通过 TaskGraph 系统来异步完成一些自定义任务 支持原生的 ...

  4. javascript 同步加载与异步加载

    HTML 4.01 的script属性 charset: 可选.指定src引入代码的字符集,大多数浏览器忽略该值. defer: boolean, 可选.延迟脚本执行,相当于将script标签放入页面 ...

  5. Javascript 文件的同步加载与异步加载

    HTML 4.01 的script属性 charset: 可选.指定src引入代码的字符集,大多数浏览器忽略该值.defer: boolean, 可选.延迟脚本执行,相当于将script标签放入页面b ...

  6. 关于requireJS的同步加载和异步加载

    这篇随笔主要记录require('name')和require(['name1','name2'])在同步和异步加载使用的区别 1.require('name')同步加载模块的形式 define(fu ...

  7. AJAX中的同步加载与异步加载

    AJAX是四个单词的简写,其中Asynchronous即异步的意思,异步的链接可以同时发起多个,并且不会阻止JS代码执行.与之对应的概念是同步,同步的链接在同一时刻只会有一个,并且会阻止后续JS代码的 ...

  8. Jquery前端分页插件pagination同步加载和异步加载

    上一篇文章介绍了Jquery前端分页插件pagination的基本使用方法和使用案例,大致原理就是一次性加载所有的数据再分页.https://www.jianshu.com/p/a1b8b1db025 ...

  9. C# 篇基础知识11——泛型和集合

    .NET提供了一级功能强大的集合类,实现了多种不同类型的集合,可以根据实际用途选择恰当的集合类型. 除了数组 Array 类定义在System 命名空间中外,其他的集合类都定义在System.Coll ...

随机推荐

  1. 前后端数据交互(三)——ajax 封装及调用

    有很多框架已经将 ajax 封装,需要的时候只需要调用就好,比如 jquery 是最常用的.我们为什么还需要学习 ajax 的封装呢?首先加强我们对ajax的认识,其次如果只是因为ajax请求需要引入 ...

  2. 从环境搭建到打包使用TypeScript

    目录 1.TypeScript是什么 2.TypeScript增加了什么 3.TypeScript环境的搭建 4.TypeScript的基本类型 5.TypeScrip编译选项 6.TypeScrip ...

  3. 痞子衡嵌入式:MCUXpresso IDE下将关键函数重定向到RAM中执行的几种方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是MCUXpresso IDE下将关键函数重定向到RAM中执行的几种方法. 前段时间痞子衡写了一篇 <在IAR开发环境下将关键函数重 ...

  4. ansible 批量安装yum包

    1.首先安装一下ansible yum install ansible 2.修改一下ansible的参数以防ssh过去的时候需要首次判断yes  或者no sed -i 's/#host_key_ch ...

  5. php 圆角图片处理

    /** * 把图片转换成圆角 * @param string $imgpath * @param int $radius * @return resource */ public function r ...

  6. Gotop安装

    一个方便的图形面板 Github:https://github.com/cjbassi/gotop 安装 git clone --depth 1 https://github.com/cjbassi/ ...

  7. Java统计文件中字母个数

    import java.text.DecimalFormat; import java.io.File; import java.io.FileReader; import java.io.Buffe ...

  8. C++打字小游戏

    从@小蔡编程 那里获得的灵感,原文地址:https://www.cnblogs.com/xiaocaibiancheng/p/15158997.html 那篇文章是说python写打字游戏的,本文就用 ...

  9. PHP的引用计数是什么意思?

    什么是引用计数 在PHP的数据结构中,引用计数就是指每一个变量,除了保存了它们的类型和值之外,还额外保存了两个内容,一个是当前这个变量是否被引用,另一个是引用的次数.为什么要多保存这样两个内容呢?当然 ...

  10. appium日志

    2020-10-02 00:44:10:672 [Appium] Welcome to Appium v1.16.0 2020-10-02 00:44:10:673 [Appium] Non-defa ...