[UE5] Async Loading

GamzaTori·2024년 10월 9일

UE5 C++

목록 보기
9/27

로딩화면에서 모두 로딩하거나 다른 스레드에게 로딩을 위임하거나 비동기로 하는 방법이 있다

  • 동기 함수의 경우 함수가 끝날때까지 멈추고 기다리기 때문에 마우스 뿐만 아니라 렌더링도 멈추기 때문에 게임에서 사용하기 적합하지 않다
  • 비동기 방식은 완료가 되었는지 매번 체크하거나 콜백 함수를 통해 함수 완료를 통지할 수 있다
    • 보통의 경우 콜백(델리게이트)으로 구현한다

기존의 동기 로딩에서 비동기 로딩으로 바꾸기

    // AssetManager  header
    
    DECLARE_DELEGATE_TwoParams(FAsyncLoadCompletedDelegate, const FName& /*AssetName or Label*/, UObject* /*Loaded Asset*/);
    
    FAsyncLoadCompletedDelegate test;
  • FAsyncLoadCompletedDelegate는 int처럼 하나의 타입으로 사용할 수 있다
  • test는 const FName&, UObject* 를 인자로 받는 함수만 연결해줄 수 있다

비동기 로딩 함수 추가

    // AssetManager header
    static void LoadAsyncByPath(const FSoftObjectPath& AssetPath, FAsyncLoadCompletedDelegate CompletedDelegate = FAsyncLoadCompletedDelegate());
    static void LoadAsyncByName(const FName& AssetName, FAsyncLoadCompletedDelegate CompletedDelegate = FAsyncLoadCompletedDelegate());
  • 두번째 인자의 CompletedDelegate는 함수의 포인터를 받아준다
	// cpp
    void URAssetManager::LoadAsyncByPath(const FSoftObjectPath& AssetPath, FAsyncLoadCompletedDelegate CompletedDelegate)
    {
    	if(UAssetManager::IsInitialized() == false)
    	{
    		UE_LOG(LogTemp, Error, TEXT("AssetManager must be initialized"));
    		return;
    	}
    
    	if(AssetPath.IsValid())
    	{
    		if(UObject* LoadedAsset = AssetPath.ResolveObject())
    		{
    			Get().AddLoadedAsset(AssetPath.GetAssetFName(), LoadedAsset);
    		}
    		else
    		{
    			TArray<FSoftObjectPath> AssetPaths;
    			AssetPaths.Add(AssetPath);
    
    			TSharedPtr<FStreamableHandle> Handle = GetStreamableManager().RequestAsyncLoad(AssetPaths);
    
    			Handle->BindCompleteDelegate(FStreamableDelegate::CreateLambda([AssetName = AssetPath.GetAssetFName(), AssetPath, CompletedDelegate = MoveTemp(CompletedDelegate)]()
    				{
    					UObject* LoadedAsset = AssetPath.ResolveObject();
    					Get().AddLoadedAsset(AssetName, LoadedAsset);
    					if(CompletedDelegate.IsBound())
    					{
    						CompletedDelegate.Execute(AssetName, LoadedAsset);
    					}
    				}));
    		}
    	}
    }
    
    void URAssetManager::LoadAsyncByName(const FName& AssetName, FAsyncLoadCompletedDelegate CompletedDelegate)
    {
    	if (UAssetManager::IsInitialized() == false)
    	{
    		UE_LOG(LogTemp, Error, TEXT("AssetManager must be initialized"));
    		return;
    	}
    
    	URAssetData* AssetData = Get().LoadedAssetData;
    	check(AssetData);
    
    	const FSoftObjectPath& AssetPath = AssetData->GetAssetPathByName(AssetName);
    	LoadAsyncByPath(AssetPath, CompletedDelegate);
    }
  • FStreamableHandle의 BindCompleteDeletage를 통해 함수가 완료되었을때 실행할 함수를 람다를 통해 구현
  • AssetManager와 로딩의 경우 복잡하고 어렵기 때문에 Lyra나 문서를 참고하는 것이 좋다
profile
게임 개발 공부중입니다.

0개의 댓글