轉自:http://blog.ch-wind.com/ue4%E5%BC%82%E6%AD%A5%E8%BD%BD%E5%85%A5%E8%B5%84%E6%BA%90/html
全部的「硬」指針指向的資源都會被UE4在啓動時進行載入,爲了防止某些狀況下引起的巨大延遲,必要的時候咱們須要使用異步資源載入系統。app
本文參考:https://docs.unrealengine.com/latest/INT/Programming/Assets/AsyncLoading/index.html進行整理。同時也是研究引擎的記錄。異步
對於異步載入有兩個類很重要:FStringAssetReferences和TAssetPtr。編輯器
FStringAssetReferences是對資源(Asset)的「軟」引用,這個結構在BP中使用起來就像是UObject指針同樣。而TAssetPtr是對FStringAssetReferences的一個弱引用封裝,同時規範所指向的類型,能夠在須要的時候調用Get()來解析到具體的資源。函數
爲了不理解上的誤差,來實際測試一次是最快的。在代碼中添加以下屬性:測試
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Test) FStringAssetReference tf; UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Test) TAssetPtr<UTexture2D> ttp;
FstringAssetReference在可視化編輯器中顯示以下,確實是能夠看成UObject指針來使用:this
TAssetPtr則顯示以下:spa
大多數時候,異步載入一個單獨的資源基本沒什麼意義,除非他真的很大。若是要批量異步載入資源的話,就須要用到Object Libraries。這個是Content brower用來進行資源篩選和顯示的類,在遊戲邏輯中使用也是能夠的。指針
if (!ObjectLibrary) { ObjectLibrary = UObjectLibrary::CreateLibrary(BaseClass, false, GIsEditor); ObjectLibrary->AddToRoot(); } ObjectLibrary->LoadAssetDataFromPath(TEXT("/Game/PathWithAllObjectsOfSameType"); if (bFullyLoad) { ObjectLibrary->LoadAssetsFromAssetData(); }
上面的代碼對指定的目錄建立了一個Library,而且資源進行了載入操做。第二個步驟並非必須的:code
TArray<FAssetData> AssetDatas; ObjectLibrary->GetAssetDataList(AssetDatas); for (int32 i = 0; i < AssetDatas.Num(); ++i) { FAssetData& AssetData = AssetDatas[i]; const FString* FoundTypeNameString = AssetData.TagsAndValues.Find(GET_MEMBER_NAME_CHECKED(UAssetObject,TypeName)); if (FoundTypeNameString && FoundTypeNameString->Contains(TEXT("FooType"))) { return AssetData; } }
上面的代碼在ObjectLibrary中進行篩選並將找到的第一個資源返回。
獲得AssetData以後能夠將其轉換爲FStringAssetReference,而後使用StreamableManager進行異步載入。
void UGameCheatManager::GrantItems() { TArray<FStringAssetReference> ItemsToStream; FStreamableManager& Streamable = UGameGlobals::Get().StreamableManager; for(int32 i = 0; i < ItemList.Num(); ++i) { ItemsToStream.AddUnique(ItemList[i].ToStringReference()); } Streamable.RequestAsyncLoad(ItemsToStream, FStreamableDelegate::CreateUObject(this, &UGameCheatManager::GrantItemsDeferred)); } void UGameCheatManager::GrantItemsDeferred() { for(int32 i = 0; i < ItemList.Num(); ++i) { UGameItemData* ItemData = ItemList[i].Get(); if(ItemData) { MyPC->GrantItem(ItemData); } } }
StreamableManager能夠對傳遞給他的StringReference所引用的資源所有進行載入操做。上面的例子中ItemList的定義爲TArray< TAssetPtr<UGameItem> >。也就說針對一個弱引用的列表,得到全部的StringReference以後傳遞給StreamableManager進行一次性的異步載入。載入以後會調用回調函數以便及時進行處理。在回調函數以前,全部的引用都會被StreamableManager保留,防止其被垃圾回收。
如上,將StreamableManager和Object Libaries進行組合使用,便可實現異步的資源載入了。