[UE4]UImage控件异步加载资源并设置图片内容

UE 异步加载是指在 Unreal Engine 中使用异步加载技术,使得游戏对象(比如静态网格、贴图、声音等)可以在不影响游戏运行的情况下逐步加载。这种方式可以优化游戏性能和降低内存占用,提高游戏的流畅度和稳定性。

自定义Image控件实现资源异步加载并设置图片:C++新建类UImageAsyn继承UImage实现图片异步加载设置。

1.包含必须的模块

//在 xx项目名字.Build.cs 文件中引入"Paper2D","SlateCore"模块,否则编译无法通过
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UnLua", "UMG", "Paper2D", "Slate", "SlateCore" });

2.代码实现自定义控件ImageAsyn

ImageAsyn.h

// 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
};

ImageAsyn.cpp

// 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

3.UMG蓝图调用测试

将自定义ImageAsyn控件拖入到UMG蓝图中,调用ImageAsyn控件函数SetImgWithPathAsyn()测试异步加载设置。

[UE4]UImage控件异步加载资源并设置图片内容_第1张图片

你可能感兴趣的:(UE4,ue4,自定义Image控件)