UE 异步加载是指在 Unreal Engine 中使用异步加载技术,使得游戏对象(比如静态网格、贴图、声音等)可以在不影响游戏运行的情况下逐步加载。这种方式可以优化游戏性能和降低内存占用,提高游戏的流畅度和稳定性。
自定义Image控件实现资源异步加载并设置图片:C++新建类UImageAsyn继承UImage实现图片异步加载设置。
//在 xx项目名字.Build.cs 文件中引入"Paper2D","SlateCore"模块,否则编译无法通过
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UnLua", "UMG", "Paper2D", "Slate", "SlateCore" });
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/Image.h"
#include "ImageAsyn.generated.h"
DECLARE_DYNAMIC_DELEGATE_OneParam(FSetImgResultDelegate, bool, bSucced);
/**
* UImage组件异步加载资源并设置图片内容
*/
UCLASS()
class BOMBERMAN_API UImageAsyn : public UImage
{
GENERATED_BODY()
public:
///
/// 设置图片:异步/同步 加载
///
UFUNCTION(BlueprintCallable)
void SetImgWithPath(FString ImgPath, bool bMatchSize, bool bAsyn, FSetImgResultDelegate InDelegate);
///
/// 设置图片:同步 加载
///
///
///
UFUNCTION(BlueprintCallable)
void SetImgWithPathSyn(FString ImgPath, bool bMatchSize, FSetImgResultDelegate InDelegate);
///
/// 设置图片:异步 加载
///
///
///
UFUNCTION(BlueprintCallable)
void SetImgWithPathAsyn(FString ImgPath, bool bMatchSize, FSetImgResultDelegate InDelegate);
UFUNCTION()
void SetImgAsset(UObject* assetObject, FSetImgResultDelegate InDelegate);
protected:
UPROPERTY()
FString mImgPath;
UPROPERTY()
bool mBMatchSize;
UFUNCTION()
FSlateBrush MakeBrushFromSprite(UPaperSprite* Sprite, int32 Width, int32 Height);
UFUNCTION()
void OnAssetAsynLoadedTwoParam(FSoftObjectPath SoftPath, FSetImgResultDelegate InDelegate);
#if WITH_EDITOR
public:
UFUNCTION(BlueprintCallable)
void TestFunc();
#endif
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "ImageAsyn.h"
#include
#include
void UImageAsyn::SetImgWithPath(FString ImgPath, bool bMatchSize, bool bAsyn, FSetImgResultDelegate InDelegate)
{
if (bAsyn)
{
this->SetImgWithPathAsyn(ImgPath, bMatchSize, InDelegate);
}
else
{
this->SetImgWithPathSyn(ImgPath, bMatchSize, InDelegate);
}
}
void UImageAsyn::SetImgWithPathSyn(FString ImgPath, bool bMatchSize, FSetImgResultDelegate InDelegate)
{
this->mImgPath = ImgPath;
this->mBMatchSize = bMatchSize;
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgWithPathSyn(),imgPath=[%s],bMatchSize=[%s]"), *ImgPath, bMatchSize ? TEXT("True") : TEXT("False"));
#endif
bool bShortPackageName = FPackageName::IsShortPackageName(this->mImgPath);
if (bShortPackageName)
{
#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
UE_LOG(LogTemp, Error, TEXT("UImageAsyn::SetImgWithPathSyn(),imgPath =[%s],bShortPackageName=[false],You must pass in fully qualified palified package names"), *ImgPath);
#endif
this->SetBrushFromTexture(nullptr, this->mBMatchSize);
InDelegate.ExecuteIfBound(false);
return;
}
FSoftObjectPath SoftPath = FSoftObjectPath(ImgPath);
if (!SoftPath.IsValid())
{
#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
UE_LOG(LogTemp, Error, TEXT("UImageAsyn::SetImgWithPathSyn(),imgPath =[%s],SoftPath.IsValid=[false],Failed!!"), *ImgPath);
#endif
this->SetBrushFromTexture(nullptr, this->mBMatchSize);
InDelegate.ExecuteIfBound(false);
return;
}
UObject* myAsset = SoftPath.ResolveObject();
if (nullptr == myAsset)
{
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgWithPathSyn(),TryLoad(),imgPath =[%s]"), *ImgPath);
#endif
myAsset = SoftPath.TryLoad();
this->SetImgAsset(myAsset, InDelegate);
}
else
{
this->SetImgAsset(myAsset, InDelegate);
}
}
void UImageAsyn::SetImgWithPathAsyn(FString ImgPath, bool bMatchSize, FSetImgResultDelegate InDelegate)
{
this->mImgPath = ImgPath;
this->mBMatchSize = bMatchSize;
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgWithPathAsyn(),imgPath=[%s],bMatchSize=[%s]"), *(this->mImgPath), this->mBMatchSize ? TEXT("True") : TEXT("False"));
#endif
bool bShortPackageName = FPackageName::IsShortPackageName(this->mImgPath);
if (bShortPackageName)
{
#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
UE_LOG(LogTemp, Error, TEXT("UImageAsyn::SetImgWithPathAsyn(),imgPath =[%s],bShortPackageName=[false],You must pass in fully qualified palified package names"), *ImgPath);
#endif
this->SetBrushFromTexture(nullptr, this->mBMatchSize);
InDelegate.ExecuteIfBound(false);
return;
}
FSoftObjectPath SoftPath = FSoftObjectPath(ImgPath);
if (!SoftPath.IsValid())
{
#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
UE_LOG(LogTemp, Error, TEXT("UImageAsyn::SetImgWithPathAsyn(),imgPath =[%s],SoftPath.IsValid=[false],Failed!!"), *ImgPath);
#endif
this->SetBrushFromTexture(nullptr, this->mBMatchSize);
InDelegate.ExecuteIfBound(false);
return;
}
UObject* myAsset = SoftPath.ResolveObject();
if (nullptr == myAsset)
{
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgWithPathAsyn(),RequestAsyncLoad(),imgPath =[%s]"), *ImgPath);
#endif
UAssetManager::GetStreamableManager().RequestAsyncLoad(SoftPath, FStreamableDelegate::CreateUObject(this, &UImageAsyn::OnAssetAsynLoadedTwoParam, SoftPath, InDelegate));
}
else
{
this->SetImgAsset(myAsset, InDelegate);
}
}
void UImageAsyn::OnAssetAsynLoadedTwoParam(FSoftObjectPath SoftPath, FSetImgResultDelegate InDelegate)
{
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::OnAssetAsynLoadedTwoParam(),RequestAsyncLoad(),imgPath =[%s],SoftPath.IsValid=[false],Failed!!"), *(this->mImgPath));
#endif
UObject* myAsset = SoftPath.ResolveObject();
this->SetImgAsset(myAsset, InDelegate);
}
void UImageAsyn::SetImgAsset(UObject* assetObject, FSetImgResultDelegate InDelegate)
{
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgAsset(),start,imgPath=[%s],bMatchSize=[%s]"), *(this->mImgPath), this->mBMatchSize ? TEXT("True") : TEXT("False"));
#endif
if (nullptr == assetObject)
{
#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
UE_LOG(LogTemp, Error, TEXT("UImageAsyn::SetImgAsset(),imgPath =[%s],nullptr == assetObject,Failed!!"), *(this->mImgPath));
#endif
this->SetBrushFromTexture(nullptr, this->mBMatchSize);
InDelegate.ExecuteIfBound(false);
return;
}
UTexture2D* textrue = Cast(assetObject);
if (nullptr != textrue)
{
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgAsset(),UTexture2D,imgPath=[%s],bMatchSize=[%s]"), *(this->mImgPath), this->mBMatchSize ? TEXT("True") : TEXT("False"));
#endif
this->SetBrushFromTexture(textrue, this->mBMatchSize);
InDelegate.ExecuteIfBound(true);
}
else
{
UPaperSprite* paperSprite = Cast(assetObject);
if (nullptr != paperSprite)
{
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgAsset(),UPaperSprite,imgPath=[%s],bMatchSize=[%s]"), *(this->mImgPath), this->mBMatchSize ? TEXT("True") : TEXT("False"));
#endif
if (this->mBMatchSize)
{
FSlateBrush brush = this->MakeBrushFromSprite(paperSprite, 0, 0);
this->SetBrush(brush);
InDelegate.ExecuteIfBound(true);
}
else
{
FSlateBrush brush;
brush.ImageSize = this->Brush.ImageSize;
brush.Margin = this->Brush.Margin;
brush.Tiling = this->Brush.Tiling;
brush.SetResourceObject(assetObject);
brush.DrawAs = this->Brush.DrawAs;
brush.Mirroring = this->Brush.Mirroring;
this->SetBrush(brush);
InDelegate.ExecuteIfBound(true);
}
}
else
{
UMaterialInstance* material = Cast(assetObject);
if (nullptr != material)
{
#if WITH_EDITOR
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::SetImgAsset(),UMaterialInstance,imgPath=[%s],bMatchSize=[%s]"), *(this->mImgPath), this->mBMatchSize ? TEXT("True") : TEXT("False"));
#endif
this->SetBrushFromMaterial(material);
InDelegate.ExecuteIfBound(true);
}
else
{
#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
UE_LOG(LogTemp, Error, TEXT("UImageAsyn::SetImgAsset(),Cast Failed,imgPath=[%s],bMatchSize=[%s]"), *(this->mImgPath), this->mBMatchSize ? TEXT("True") : TEXT("False"));
#endif
this->SetBrushFromTexture(nullptr, this->mBMatchSize);
InDelegate.ExecuteIfBound(false);
}
}
}
}
FSlateBrush UImageAsyn::MakeBrushFromSprite(UPaperSprite* Sprite, int32 Width, int32 Height)
{
if (Sprite)
{
const FSlateAtlasData atlasData = Sprite->GetSlateAtlasData();
const FVector2D Size = atlasData.GetSourceDimensions();
FSlateBrush brush;
brush.SetResourceObject(Sprite);
Width = Width > 0 ? Width : Size.X;
Height = Height > 0 ? Height : Size.Y;
brush.ImageSize = FVector2D(Width, Height);
return brush;
}
return FSlateNoResource();
}
#if WITH_EDITOR
void UImageAsyn::TestFunc()
{
UE_LOG(LogTemp, Log, TEXT("UImageAsyn::TestFunc"));
}
#endif
将自定义ImageAsyn控件拖入到UMG蓝图中,调用ImageAsyn控件函数SetImgWithPathAsyn()测试异步加载设置。