BlueRoseNote/03-UnrealEngine/Gameplay/Gameplay/AssetManager/AssetManager系列之TAssetPtr、FStreamableManager、FStreamableHandle、FSoftObjectPath.md
2023-06-29 11:55:02 +08:00

9.7 KiB
Raw Blame History

TAssetPtr

因为在wiki上已经有介绍TAssetPtr的内容了所以我就直接翻译了并且在末尾给予一定的补充。以下是翻译自wiki的内容

一般情况下我们无需将这个场景中所有Asset都加载了再进入游戏我们可以先加载必要Asset在进入场景后异步加载剩余的非必要资源。而TAssetPtr可以解决这个问题

TAssetPtr类似于标准指针其区别在于TAssetPtr指向的资产可能已经加载也可能还没有加载如果资产没有加载则它包含加载该资产所需的信息。TAssetPtr属于弱指针

一个简单的引用Asset的方法就是创建带有UProperty标记的TAssetPtr成员变量并且在编辑器中指定想要加载的Asset。

本质上是TSoftClassPtr包含了FSoftObjectPtr对象。可以通过FSoftObjectPath构造用其监视Asset的状态

类型

变量 描述
TAssetPtr 指向尚未加载但可以根据请求加载的资产的指针
TAssetSubclassOf 指向已定义的基类的子类的指针该子类尚未加载但可以根据请求加载。用于指向蓝图而不是基本component。大概是因为蓝图是Asset

关键功能

.h

/** 定义Asset指针. 别忘记添加UPROPERTY标记 */
UPROPERTY(EditAnywhere)
TAssetPtr<MyClass> MyAssetPointer;

/** 定义子类版本. */
UPROPERTY(EditAnywhere)
TAssetSubclassOf<MyBaseClass> MyAssetSubclassOfPointer;

.cpp

// 调用IsValid()去测试这个AssetPtr是不是指向一个有效的UObject
MyAssetPointer.IsValid();

//调用Get()来返回其指向的UObject在UObject存在的情况下
MyAssetPointer.Get();

/** 特别注意TAssetSubclassOf的Get()它返回的是UClass的指针 */
MyAssetSubclassOfPointer.Get()
/** 要正确使用UClass指针必须使用GetDefaultObject<T>()来获得指向UObject或派生类的指针 */
MyAssetSubclassOfPointer.Get()->GetDefaultObject<MyBaseClass>()

// 调用ToStringReference()返回希望加载的Asset的FStringAssetReference
MyAssetPointer.ToStringReference();

如何使用

变量 描述
FStreamableManager 运行时的Asset流控制管理器这是用户定义的对象应该被定义在类似GameInstance之类的方便访问的对象中。
FStringAssetReference 一个包含Asset应用字符串的结构体能对Asset进行弱引用。
Asset载入器

FStreamableManager是异步资源加载器最好定义在类似GameInstance之类持久性对象中原因有下

  1. 访问方便,这使得在需要时加载资产变得很容易。
  2. 具备持久性因为你永远不想在加载对象时丢失或销毁对FStreamableManager的引用。
使用方法
简单异步载入

允许您加载单个资产并获得它的强引用。这意味着在您使用unload手动卸载它之前它永远不会被垃圾回收。(这个 方法已经被废弃请使用RequestAsyncLoad并设置bManageActiveHandle为true)

// the .h
TAssetPtr<ABaseItem> MyItem;

// the .cpp
FStringAssetReference AssetToLoad
AssetToLoad = MyItem.ToStringReference();
AssetLoader.SimpleAsyncLoad(AssetToLoad);
请求式异步载入
//the .h
TArray< TAssetPtr<ABaseItem> > MyItems;

// the .cpp
TArray<FStringAssetReference> AssetsToLoad
for(TAssetPtr<ABaseItem>& AssetPtr : MyItems) // C++11 ranged loop
{
     AssetsToLoad.AddUnique(AssetPtr.ToStringReference());
}
AssetLoader.RequestAsyncLoad(AssetsToLoad, FStreamableDelegate::CreateUObject(this, &MyClass::MyFunctionToBeCalledAfterAssetsAreLoaded));

PS.实际看过代码之后发现这个RequestAsyncLoad还有一个回调版本的。

/** 
 * This is the primary streamable operation. Requests streaming of one or more target objects. When complete, a delegate function is called. Returns a Streamable Handle.
 *
 * @param TargetsToStream		Assets to load off disk
 * @param DelegateToCall		Delegate to call when load finishes. Will be called on the next tick if asset is already loaded, or many seconds later
 * @param Priority				Priority to pass to the streaming system, higher priority will be loaded first
 * @param bManageActiveHandle	If true, the manager will keep the streamable handle active until explicitly released
 * @param bStartStalled			If true, the handle will start in a stalled state and will not attempt to actually async load until StartStalledHandle is called on it
 * @param DebugName				Name of this handle, will be reported in debug tools
 */
TSharedPtr<FStreamableHandle> RequestAsyncLoad(const TArray<FSoftObjectPath>& TargetsToStream, FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = DefaultAsyncLoadPriority, bool bManageActiveHandle = false, bool bStartStalled = false, const FString& DebugName = TEXT("RequestAsyncLoad ArrayDelegate"));
TSharedPtr<FStreamableHandle> RequestAsyncLoad(const FSoftObjectPath& TargetToStream, FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = DefaultAsyncLoadPriority, bool bManageActiveHandle = false, bool bStartStalled = false, const FString& DebugName = TEXT("RequestAsyncLoad SingleDelegate"));

/** Lambda Wrappers. Be aware that Callback may go off multiple seconds in the future. */
TSharedPtr<FStreamableHandle> RequestAsyncLoad(const TArray<FSoftObjectPath>& TargetsToStream, TFunction<void()>&& Callback, TAsyncLoadPriority Priority = DefaultAsyncLoadPriority, bool bManageActiveHandle = false, bool bStartStalled = false, const FString& DebugName = TEXT("RequestAsyncLoad ArrayLambda"));
TSharedPtr<FStreamableHandle> RequestAsyncLoad(const FSoftObjectPath& TargetToStream, TFunction<void()>&& Callback, TAsyncLoadPriority Priority = DefaultAsyncLoadPriority, bool bManageActiveHandle = false, bool bStartStalled = false, const FString& DebugName = TEXT("RequestAsyncLoad SingleLambda"));
使用Asset

当你的Asset加载完成别忘记调用Get()来取得它。

MyItem.Get(); // returns a pointer to the LIVE UObject

本人额外添加的内容(一些有用的东西)

FStreamableManager

/** 
 * 同步版本的载入函数用于载入多个一组资源返回一个handle。
 * 
 * @param TargetsToStream		Assets to load off disk
 * @param bManageActiveHandle	If true, the manager will keep the streamable handle active until explicitly released
 * @param DebugName				Name of this handle, will be reported in debug tools
 */
TSharedPtr<FStreamableHandle> RequestSyncLoad(const TArray<FSoftObjectPath>& TargetsToStream, bool bManageActiveHandle = false, const FString& DebugName = TEXT("RequestSyncLoad Array"));
TSharedPtr<FStreamableHandle> RequestSyncLoad(const FSoftObjectPath& TargetToStream, bool bManageActiveHandle = false, const FString& DebugName = TEXT("RequestSyncLoad Single"));

/** 
 * 同步版本的载入函数用于载入单个资源返回UObject的指针。如果没有找到则返回空指针。
 * 
 * @param Target				Specific asset to load off disk
 * @param bManageActiveHandle	If true, the manager will keep the streamable handle active until explicitly released
 * @param RequestHandlePointer	If non-null, this will set the handle to the handle used to make this request. This useful for later releasing the handle
 */
UObject* LoadSynchronous(const FSoftObjectPath& Target, bool bManageActiveHandle = false, TSharedPtr<FStreamableHandle>* RequestHandlePointer = nullptr);

FStreamableHandle

同步或者异步加载的句柄只要句柄处于激活状态那么Asset就不会被回收。你可以句柄来控制Asset以及绑定相应的委托。

/** Bind delegate that is called when load completes, only works if loading is in progress. This will overwrite any already bound delegate! */
bool BindCompleteDelegate(FStreamableDelegate NewDelegate);

/** Bind delegate that is called if handle is canceled, only works if loading is in progress. This will overwrite any already bound delegate! */
bool BindCancelDelegate(FStreamableDelegate NewDelegate);

/** Bind delegate that is called periodically as delegate updates, only works if loading is in progress. This will overwrite any already bound delegate! */
bool BindUpdateDelegate(FStreamableUpdateDelegate NewDelegate);

/**
 * Blocks until the requested assets have loaded. This pushes the requested asset to the top of the priority list,
 * but does not flush all async loading, usually resulting in faster completion than a LoadObject call
 *
 * @param Timeout				Maximum time to wait, if this is 0 it will wait forever
 * @param StartStalledHandles	If true it will force all handles waiting on external resources to try and load right now
 */
EAsyncPackageState::Type WaitUntilComplete(float Timeout = 0.0f, bool bStartStalledHandles = true);

/** Gets list of assets references this load was started with. This will be the paths before redirectors, and not all of these are guaranteed to be loaded */
void GetRequestedAssets(TArray<FSoftObjectPath>& AssetList) const;

/** Adds all loaded assets if load has succeeded. Some entries will be null if loading failed */
void GetLoadedAssets(TArray<UObject *>& LoadedAssets) const;

/** Returns first asset in requested asset list, if it's been successfully loaded. This will fail if the asset failed to load */
UObject* GetLoadedAsset() const;

/** Returns number of assets that have completed loading out of initial list, failed loads will count as loaded */
void GetLoadedCount(int32& LoadedCount, int32& RequestedCount) const;

/** Returns progress as a value between 0.0 and 1.0. */
float GetProgress() const;

FSoftObjectPath

一个包含对象的引用字符串的结构体。它可以对按需加载的资产进行弱引用。可以使用UProperties进行标记使得它可以在编辑器中显示并且可以指定资源。

可以使用TryLoad进行Asset载入返回UObject指针为空则表示载入失败。