概述
虛幻引擎4中有幾個新系統,使得可以更加輕松地異步加載資源數據,這些系統代替了虛幻引擎3中的免搜索內容包中存在的很多功能。這些新方法既可以在開發數據應用也可以在設備上的烘焙數據上進行應用,所以您不必保留兩個根據需要加載數據的代碼路徑。有兩種通用的方法可以供您根據需要來引用及加載數據。
FStringAssetReferences 和TAssetPtr
美術師或設計師引用資源的最簡單的方法是,創建一個UProperty 強指針,並賦予其一個類目。在虛幻引擎4中,如果您使用強指針UObject 屬性引用一個資源,那么當加載包含該屬性的對象時將會加載那個資源(通過把對象放置在地圖中,或者通過從類似於游戲信息這樣的東西中進行引用該對象)。如果您不關心是否在游戲啟動時能夠100%地加載您的資源。如果您想讓 美術師/設計師 使用和強指針一樣的用戶界面來引用特定的資源,而不是總是加載引用的資源,請使用 FStringAssetReference 或 TAssetPtr 。
FStringAssetReference 是一個簡單的結構體,包含了一個具有資源完整名稱的字符串。如果您在類中創建一個那種類型的屬性,那么它將會顯示在編輯器中,就像是個 UObject * 屬性一樣。它還可以正確地處理烘焙和重定向,所以如果您有一個StringAssetReference,那么它一定可以在設備上正常工作。TAssetPtr基本上就是一個封裝了 FStringAssetReference 的 TWeakObjectPtr ,它使用一個特定的類作為模板,以便您能限制編輯器用戶界面,使其僅允許選擇特定的類。如果所引用的資源存在於內存中,那么 TAssetPtr.Get() 將返回該資源。如果該資源不在內存中,那么您那可以調用 ToStringReference() 來查找它引用的資源,並使用下面介紹的方法加載該資源,然后再次調用TAssetPtr.Get() 解除對該資源的引用。
如果美術師或設計師正在手動地設置引用,那么使用 TAssetPtrs 和 StringAssetReferences是非常適合的,但如果您想進行類似於查詢這樣的處理,查找滿足特定要求的資源,而不是加載所有資源,那么您應該使用資源注冊表及對象庫。
資源注冊表和對象庫
資源注冊表是一個存儲資源的元數據的系統,允許您搜索及查詢這些資源。編輯器使用此資源注冊表來顯示內容瀏覽器中的信息,但是您也可以從游戲性代碼使用該注冊表,來查找當前沒有加載的游戲資源的相關元數據。要想使得一個資源的數據是可搜索的,您需要給該屬性添加"AssetRegistrySearchable"標簽。查詢資源注冊表會返回FAssetData類型的對象,它包含了關於該對象的信息和一個 鍵-》值 對映射表,該映射表包含了標記為可搜索的屬性。
處理成組的未加載的資源的最簡單方法是使用 ObjectLibrary 。ObjectLibrary 是一個對象,包含了一系列繼承共享基類的未加載對象或者未加載對象的FAssetData 。您可以通過提供一個搜索路徑來加載一個對象庫,它將加載那個路徑中的所有資源。這是非常有用的,因為您可以為不同類型指定您的部分內容文件夾,且 美術師/設計師 不需要手動編輯清單表就可以添加新的資源。這里是一個示例,展示了如何使用一個對象庫來從磁盤加載AssetData:
if(!ObjectLibrary){ObjectLibrary=ConstructObject<UObjectLibrary>(UObjectLibrary::StaticClass());ObjectLibrary->ObjectBaseClass=BaseClass;ObjectLibrary->UseWeakReferences(GIsEditor);ObjectLibrary->AddToRoot();}ObjectLibrary->LoadAssetDataFromPath(TEXT("/Game/PathWithAllObjectsOfSameType");if(bFullyLoad){ObjectLibrary->LoadAssetsFromAssetData();}
在這個示例中,它創建了一個新的對象庫,關聯了一個基類,然后加載了給定路徑中的所有資源數據。接着選擇性地加載真正的資源。如果資源很小,或者如果您正在進行烘焙且需要確保烘焙所有內容,那么您則需要完全地加載這些資源。只要您在烘焙過程中執行一次資源注冊表查詢,並加載返回的資源,您的對象庫就可以正常地在烘焙數據中發揮作用,就像在開發過程中的處理一樣。一旦把資源數據放入到了一個ObjectLibrary 中,您可以進行查詢並選擇性地加載特定的資源。這里是示例,展示了如何進行查詢:
TArray<FAssetData>AssetDatas;ObjectLibrary->GetAssetDataList(AssetDatas);for(int32 i =0; i <AssetDatas.Num();++i){FAssetData&AssetData=AssetDatas[i];constFString*FoundTypeNameString=AssetData.TagsAndValues.Find(GET_MEMBER_NAME_CHECKED(UAssetObject,TypeName));if(FoundTypeNameString&&FoundTypeNameString->Contains(TEXT("FooType"))){returnAssetData;}}
在這個示例中,它搜索對象庫並查找任何具有 TypeName 文本域且該文本域中包含 "FooType" 的對象,然后返回第一次查找到的對象。一旦有了此 AssetData ,您可以調用 ToStringReference() 來把它轉換成一個 FStringAssetReference ,然后您可以使用下一個系統進行異步加載。
StreamableManager(動態加載管理器)和異步加載
現在,您具有一個引用了磁盤上一個資源的 FStringAssetReference ,那么怎樣真正地異步加載它哪? FStreamableManager是完成這個處理的最簡單方法。首先,您需要創建一個 FStreamableManager ,我建議你把它放到某個全局游戲單例對象中,比如在 DefaultEngine.ini中使用 GameSingletonClassName 指定的對象。然后,您可以把 StringAssetReference 傳給該對象,並啟動進行加載。SynchronousLoad將會進行簡單的、阻礙加載,並返回該對象。這種方法對於較小的對象可能很好,但是它可能會使您的主線程停頓時間過長。出現那種情況,您將需要使用 RequestAsyncLoad ,它將會異步地加載一組資源,並在完成后調用一個代理。這里是一個示例:
voidUGameCheatManager::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));}voidUGameCheatManager::GrantItemsDeferred(){for(int32 i =0; i <ItemList.Num();++i){UGameItemData*ItemData=ItemList[i].Get();if(ItemData){MyPC->GrantItem(ItemData);}}}
在這個示例中,ItemList 是一個 TArray< TAssetPtr<UGameItem> > ,由設計人員在編輯器中進行修改。這段代碼迭代那個列表,將列表項轉換為 StringReferences ,並將它們進行排隊。當所有列表項都加載后(或者由於缺失列表項而不能加載),它將在代理中調用已通過的相關處理。該代理然后迭代同樣的列表項,區分它們,並把它們提供給一個玩家。StreamableManager 在調用該代理之前,將保持到任何它所加載的對象的強引用,所以在調用該代理之前,您可以確保您想異步加載的任何對象都沒有被垃圾回收。當調用該代理后,StreamableManager 釋放這些引用,所以您想確保它們一直存在,您需要在其他地方對它們進行強引用。
您可以使用同樣的方法來異步加載 FAssetDatas ,僅需在它們上面調用 ToStringReference ,把它們添加到一個數組中,然后使用一個代理調用RequestAsyncLoad 。該代理可以是您想操作的任何內容,所以如果需要,你可以傳入負載信息。通過把結合使用上述的方法,您應該可以設置一個高效加載游戲中的任何資源的系統。轉換直接訪問內存的游戲代碼來處理異步加載將會花費一些時間,但是之后您的游戲停頓將變得非常少,並且內存使用量會更低。
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow
