0、需求
假設我們在做一款偷菜遊戲,推出了一系列花裏胡哨的農社與作物皮膚作為氪金點。玩家扮演老王在其他玩家的田地中偷菜,玩家可能會有很多,但可能會有許多人使用最新推出的皮膚,故需要實現一套動態關卡加載與資源管理,使得切換過程中儘可能絲滑無感。
1、動態加載Level
首先給出答案,然後面向答案編程
// 設置一個流關卡顯示與隱藏
void ULevelStreaming::SetShouldBeVisible(const bool bInShouldBeVisible)
想要顯示或隱藏流關卡,需要先有一個流關卡
ULevelStreamingDynamic* ULevelStreamingDynamic::LoadLevelInstanceBySoftObjectPtr(
UObject* WorldContextObject, // 當前的關卡World
const TSoftObjectPtr<UWorld> Level, // 要加載的關卡的軟引用
const FVector Location,
const FRotator Rotation,// 關卡在主關卡中的偏移和旋轉
bool& bOutSuccess, // 是否找到了這個關卡併成功加載
const FString& OptionalLevelNameOverride// 不曉得做啥的,可空
)
ULevelStreamingDynamic是流關卡類型,繼承自ULevelStreaming,因此也可以使用ULevelStreaming::SetShouldBeVisible。
2、非阻塞加載
使用上面的接口後會發現,這個函數會阻塞主線程的執行,體驗並不好,因此需要以異步的方式提前加載場景資源。
// 這個接口默認執行異步加載,可在項目設置中調整
TSharedPtr<FStreamableHandle> UAssetManager::LoadAssetList(
const TArray<FSoftObjectPath>& AssetList, // 地圖路徑
FStreamableDelegate DelegateToCall, // 完成的回調
TAsyncLoadPriority Priority,
const FString& DebugName
)
除了地圖路徑以外,其他參數都可空
實際調用如下
TSharedPtr<FStreamableHandle> streamHandle =
UAssetManager::Get().LoadAssetList(
TArray<FSoftObjectPath>{Level.ToSoftObjectPath()},
onComplate
);
onComplate為加載完成時的調用,可以在其中按照第一節的步驟創建ULevelStreamingDynamic對象並設置顯隱。
3、資源釋放
資源管理一般是由UAssetManager決定,理論上有GC在不需要關心這部分。
void FStreamableManager::Unload(const FSoftObjectPath& Target)
通過FStreamableHandle的GetOwningManager()接口拿到對應的Manager並傳入資源對應路徑即可,但會導致其他引用到這裏的資源失效,故十分不建議這麼做。