ue4-异步加载资源

  • 异步加载资源

  • ue中的异步加载分为两种模式,具体源码在 AsyncLoading.cpp

    1. 主线程分帧加载。
    2. 多线程加载。
  • 可以通过接口判断当前的异步模式是那种模式。

    1
    const bool bIsMultithreaded = FAsyncLoadingThread::IsMultithreaded();

思路

  1. 一个FVCharPartInfo物件结构体,里面id和TAssetPtr对mesh资源的的指针。
  2. 一个UItemInfoDatabase物件数据库,里面有一个物件列表TArray
  3. 一个全局单例类USolusDataSingleton,里面有个资源加载器struct FStreamableManager* AssetLoader和物件数据库class UItemInfoDatabase* ItemDatabase
  4. 使用加载器异步请求加载物件数据库里的物件列表
    有个不好的地方就是,绑定加载完的回调指针,不能在获取对应的加载的对象

实现

  1. 物件和数据库都在 ItemInfoDatabase.h 中(***++ps++:***如果修改了 FVCharPartInfo,记得要重新启动一下编辑器,否则这个结构体在编辑器中没有变化)

    • ItemInfoDatabase.h
      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
      #pragma once
      #include "Engine/DataAsset.h"
      #include "ItemInfoDatabase.generated.h"

      USTRUCT()
      struct FVCharPartInfo
      {
      GENERATED_USTRUCT_BODY()
      UPROPERTY(EditAnywhere, Category = "DATA")
      int32 MeshID;

      UPROPERTY(EditAnywhere, Category = "DATA")
      TAssetPtr<USkeletalMesh> MeshResource;

      FVCharPartInfo()
      {
      MeshID = 0;
      MeshResource = FStringAssetReference("");
      }
      };

      //Holds a dynamic collection of character parts
      UCLASS(BlueprintType)
      class UItemInfoDatabase : public UDataAsset
      {
      GENERATED_UCLASS_BODY()
      UPROPERTY(EditAnywhere, Category = "Model List") //Exposes the array as editable on editor
      TArray<FVCharPartInfo> MeshList;

      public:
      UItemInfoDatabase();
      };
    • ItemInfoDatabase.cpp
      1
      2
      3
      4
      5
      6
      7
      ItemInfoDatabase.cpp
      #include "MySlate.h"
      #include "ItemInfoDatabase.h"

      UItemInfoDatabase::UItemInfoDatabase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
      {
      }
  2. 在Editor中建个UItemInfoDatabase蓝图类

    • 在编辑器中把资源引用添加进去,下面的单例类会直接加载这个UitemInfoDatabase载蓝图类
      这里写图片描述
    • 添加资源的引用
      这里写图片描述
  3. 全局单例类,初始化时把数据库加进去

    • SolusDataSingleton.h
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      #pragma once
      #include "SolusDataSingleton.generated.h"

      struct FStreamableManager;
      class UItemInfoDatabase;

      UCLASS(Blueprintable, BlueprintType)
      class USolusDataSingleton : public UObject
      {
      GENERATED_BODY()
      public:
      USolusDataSingleton(const FObjectInitializer& ObjectInitializer);
      virtual ~USolusDataSingleton();

      static USolusDataSingleton* Get(); // Get method to access this object
      struct FStreamableManager* AssetLoader; // Your asset loader
      class UItemInfoDatabase* ItemDatabase;
      };
    • SolusDataSingleton.cpp
      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
      #include "MySlate.h"
      #include "SolusDataSingleton.h"

      #include "Engine.h"
      #include "Engine/StreamableManager.h"
      #include "Singleton/SolusDataSingleton.h"
      #include "Singleton/ItemInfoDatabase.h"

      USolusDataSingleton::USolusDataSingleton(const FObjectInitializer& ObjectInitializer)
      : Super(ObjectInitializer)
      {
      AssetLoader = new FStreamableManager();

      //加载itemDataBase蓝图类
      UObject* obj = AssetLoader->SynchronousLoad(FStringAssetReference(TEXT("/Game/TopDownCPP/MeshItems/MeshDateBaseBP")));
      ItemDatabase = Cast<UItemInfoDatabase>(obj);
      }

      USolusDataSingleton::~USolusDataSingleton()
      {
      if (AssetLoader)
      delete AssetLoader;
      }

      USolusDataSingleton* USolusDataSingleton::Get()
      {
      USolusDataSingleton* DataInstance = Cast<USolusDataSingleton>(GEngine->GameSingleton); //这里指定配置文件中指定的单例类
      if (!DataInstance)
      return nullptr;
      else
      return DataInstance;
      }
  4. 在BpLib中起个方法测试异步加载

    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
    //h
    UFUNCTION(BlueprintCallable, Category = "Async Load")
    static UObject* TestAsyncLoad(AMyChar* _myChar);
    //cpp
    bool UMyBpFuncLib::TestAsyncLoad(AMyChar* _myChar)
    {
    if (!_myChar)
    return false;

    FStreamableManager* BaseLoader = USolusDataSingleton::Get()->AssetLoader;
    UItemInfoDatabase* _database = USolusDataSingleton::Get()->ItemDatabase;

    if (!BaseLoader || !_database)
    return false;

    TArray<FStringAssetReference> ObjToLoad;
    for (int32 i = 0; i < _database->MeshList.Num(); ++i)
    {
    ObjToLoad.AddUnique(_database->MeshList[i].MeshResource.ToStringReference());
    }
    //请求异步加载
    BaseLoader->RequestAsyncLoad(ObjToLoad, FStreamableDelegate::CreateUObject(_myChar, &AMyChar::TestAsyncLoad));
    return true;
    }

    //回调方法
    void AMyChar::TestAsyncLoad()
    {
    FString str = FString::Printf(TEXT("--- AMyChar::TestAsyncLoad callback"));
    GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Red, str);
    }
  5. 蓝图调用测试方法
    这里写图片描述

  6. 结果
    这里写图片描述


参考资料