UE4 c++保存asset实例(含创建自定义Asset类)

这篇具有很好参考价值的文章主要介绍了UE4 c++保存asset实例(含创建自定义Asset类)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

注意

该文档的目标是创建一个uasset文件,用来保存类的实例,而不是蓝图类,类似存储在内容中的图片。
该文档是实践记录,具体理论查看参考。
如果要通过C++创建蓝图类,可以先新建C++类,然后在UE编辑器中有C++ Classes文件夹,进入后找到自己新建的C++类,右键创建蓝图类即可

参考

UE4.26.2
《大象无形》第10章,对象模型,第16章,自定义资源和编辑器
资产管理
UE4资源加载1
Creating new uasset files in code/CPP
UE中创建自定义Asset类

package 与 asset

一个资源在文件中对应uasset,在内存中对应UPackage。
UPackage序列化到本地后就是uasset文件。关于序列化详情看《大象无形》第十章。
在UE编辑器中创建一个资源,此时资源是存在内存上的,打开文件管理器是看不到资源的,只有点击了保存之后才能在文件管理器中看到asset。

保存uasset的样例

为了方便,新建一个C++第三人称项目,新建c++类MyObject继承于UObject,该类用来保存为uasset,里面可以什么都不写。这里不可以直接用UObject,UObject是抽象类,直接存会报错。而继承UObject,多了UCLASS()一系列东西。
然后在对应Character 类下实现
.h 文件添加代码

	UFUNCTION(BlueprintCallable)
	bool TestCreateAsset();
	bool GetFolderToSaveDatas(FString& OutFolderName);

.cpp 文件添加代码

bool AMyProjectCharacter::TestCreateAsset()
{
	// 获取文件保存位置
	FString saveFolder;
	if(!GetFolderToSaveDatas(saveFolder))
	{
		return false;
	}
	
	FString objectName = TEXT("MyCreateObject");
	
	// 创建包
	FString packageName = TEXT("/Game/") + saveFolder + "/" + objectName;
	UPackage* package = CreatePackage(*packageName);
	package->FullyLoad();
	
	// 创建实例
	UMyObject* myCreateObject = NewObject<UMyObject>(package, *objectName, RF_Public | RF_Standalone);
	if (IsValid(myCreateObject))
	{
		// 添加细节
	}
	
	// 保存Package
	FAssetRegistryModule::AssetCreated(myCreateObject);
	package->SetDirtyFlag(true);
	return true;
}

// 打开文件夹,获取保存的文件名
bool AMyProjectCharacter::GetFolderToSaveDatas(FString& OutFolderName)
{
	IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
	if(DesktopPlatform)
	{
		if (
			DesktopPlatform->OpenDirectoryDialog(
				nullptr,
				TEXT("Choose a folder to save asset which created, must inside Content folder"),
				FPaths::ProjectContentDir(),
				OutFolderName
			)
			)
		{
			// 绝对路径转相对路径
			FString projectContentDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir());
			if(OutFolderName.StartsWith(projectContentDir))
			{
				OutFolderName.RemoveFromStart(projectContentDir);
				return true;
			}
			else
			{
				FMessageDialog::Open(EAppMsgType::Ok,
					FText::FromString(FString::Printf(TEXT("You must select a folder inside Content folder!"))));
			}
		}
	}
	return false;
}

然后在蓝图中调用该函数,设置成按P键调用,开始游戏后调用即可。
UE4 c++保存asset实例(含创建自定义Asset类)

如果过程中报已存在同名资产包,要清空内存中的的资产包(重启不保存)和删除Content中的资产重新实验

尝试将Character实例存为uasset

有了样例之后,在创建实例那里修改就行。将UMyObject全部修改成ACharacter,然后运行游戏按P,会发现此时并没有保存package,然后进一步点击Save all,会发现刚刚创建的package存在,但是是Empty Package!此时就算点保存也是不会产生uasset的!下面用断点调试查找原因
UE4 c++保存asset实例(含创建自定义Asset类)

跑到后面发现这个if判断没有进来
UE4 c++保存asset实例(含创建自定义Asset类)

回到Actor中可以发现一个Actor可以成为资产的判断
UE4 c++保存asset实例(含创建自定义Asset类)

所以对一个对象可否产生资产可以利用该接口进行判断,已知Actor的子对象是不行的,回顾资产管理,会发现UE将资产分为两种

  • 蓝图类资产
  • 数据资产(非蓝图资产)

该文档的目的就是创建数据资产,目前发现无法将Character实例单独存为uasset,这里强调一下非蓝图资产的 NOTE
UE4 c++保存asset实例(含创建自定义Asset类)

用插件创建自定义Asset类

基本步骤

  • 自定义的资产类,继承于UObject
  • 相应的Factory类,继承与UFactory
  • 添加资产类型的注册(AssetTypeActions)

添加Editor模块

先在UE编辑器上新建空白插件MyPlugin,到Source文件夹下,复制一份MyPlugin,添加Editor模块(修改后缀),完成后Source文件结构如下

Source
  +  MyPlugin
  +    +  Private
  +    +    +  MyPlugin.cpp
  +    +  Public
  +    +    +  MyPlugin.h
  +    +  MyPlugin.Build.cs
  +  MyPluginEditor
  +    +  Private
  +    +    +  MyPluginEditor.cpp
  +    +  Public
  +    +    +  MyPluginEditor.h
  +    +  MyPluginEditor.Build.cs

修正Editor 文件夹下的文件,都添加Editor后缀,如下
MyPluginEditor.Build.cs,cs文件多添加两个模块依赖

public class MyPluginEditor : ModuleRules
{
	public MyPluginEditor(ReadOnlyTargetRules Target) : base(Target)
	{
				PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				//...
				"UnrealEd",
				"MyPlugin"
			}
			);
	}
}

MyPluginEditor.h

class FMyPluginEditorModule : public IModuleInterface

MyPluginEditor.cpp

#include "MyPluginEditor.h"

#define LOCTEXT_NAMESPACE "FMyPluginEditorModule"

void FMyPluginEditorModule::StartupModule() 
{

}

void FMyPluginEditorModule::ShutdownModule()
{

}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FMyPluginEditorModule, MyPluginEditor)

最后在 uplugin中添加Eidtor模块

	"Modules": [
		{
			"Name": "MyPlugin",
			"Type": "Runtime",
			"LoadingPhase": "Default"
		},
		{
			"Name": "MyPluginEditor",
			"Type": "Editor",
			"LoadingPhase": "Default"
		}
	]

自定义资产类及创建工厂

在插件中的MyPlugin模块新建自定义资产类MyCustomObject,继承于UObject
头文件要标注BlueprintType,不然无法创建蓝图类

UCLASS(BlueprintType)
class MYPLUGIN_API UMyCustomObject : public UObject
{
	GENERATED_BODY()
	
};

继承UFactory,添加到Editor模块中,命名MyCustomFactory,Factory类要放在Editor模块中。
添加构造函数和补充FactoryCreateNew函数
头文件

UCLASS()
class MYPLUGINEDITOR_API UMyCustomFactory : public UFactory
{
	GENERATED_BODY()
public:
	UMyCustomFactory();

	virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
};

cpp文件

#include "MyCustomFactory.h"
#include "MyCustomObject.h"

UMyCustomFactory::UMyCustomFactory()
{
	bCreateNew = true;
	bEditAfterNew = true;
	SupportedClass = UMyCustomObject::StaticClass();
}

UObject* UMyCustomFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
	UMyCustomObject* MyCustomObject = NewObject<UMyCustomObject>(InParent, InName, Flags | RF_Transactional);
	return MyCustomObject;
}

添加资产类型的注册

新建C++类CustomAssetTypeActions,继承于FAssetTypeActions_Base,实现一些必要的虚函数

class MYPLUGINEDITOR_API FCustomAssetTypeActions : public FAssetTypeActions_Base
{
public:
	FCustomAssetTypeActions(EAssetTypeCategories::Type InAssetCategory);

	virtual FColor GetTypeColor() const override;
	virtual FText GetName() const override;
	virtual UClass* GetSupportedClass() const override;
	virtual uint32 GetCategories() override;
private:
	EAssetTypeCategories::Type AssetCategory;
};
FCustomAssetTypeActions::FCustomAssetTypeActions(EAssetTypeCategories::Type InAssetCategory)
{
	AssetCategory = InAssetCategory;
}

FColor FCustomAssetTypeActions::GetTypeColor() const
{
	return FColor::Red;
}

FText FCustomAssetTypeActions::GetName() const
{
	return FText::FromName(TEXT("MyCustomObject"));
}

UClass* FCustomAssetTypeActions::GetSupportedClass() const
{
	return UMyCustomObject::StaticClass();
}

uint32 FCustomAssetTypeActions::GetCategories()
{
	return AssetCategory;
}

并在插件开始的时候进行资源注册及卸载
打开MyPluginEditor.h

class FMyPluginEditorModule : public IModuleInterface
{
public:

	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
private:
	TSharedPtr<FCustomAssetTypeActions> actionType;
};

MyPluginEditor.cpp

void FMyPluginEditorModule::StartupModule()
{
	IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
	EAssetTypeCategories::Type AssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("CustomAssetTypeActions")), FText::FromName(TEXT("自定义资源")));
	actionType = MakeShareable(new FCustomAssetTypeActions(AssetCategory));
	AssetTools.RegisterAssetTypeActions(actionType.ToSharedRef());
}

void FMyPluginEditorModule::ShutdownModule()
{
	if (FModuleManager::Get().IsModuleLoaded("AssetTools"))
	{
		IAssetTools& AssetTools = FModuleManager::Get().GetModuleChecked<FAssetToolsModule>("AssetTools").Get();
		AssetTools.UnregisterAssetTypeActions(actionType.ToSharedRef());
	}
}

自此就已经完成插件的自定义资源了,此时要重新启动插件才能进行资源注册。

尝试将自定义的资源继承于Actor

已知Actor 不是Asset,那么自定义资源继承与Actor 会怎么样呢?
UMyCustomObject的父类改成AActor,并将所有的UMyCustomObject改为AMyCustomObject,debug运行!
会发现现在居然能在内存上创建AMyCustomObject资产!但是进行保存的时候还是为Empty Package!也就是说无法存为asset!
UE4 c++保存asset实例(含创建自定义Asset类)

此时打开NewMyCustomObject,程序突然跳到一处check,GetWorld() = NULL
UE4 c++保存asset实例(含创建自定义Asset类)

程序接着走能打开一般的编辑器(Run模式下会直接崩溃关闭)
UE4 c++保存asset实例(含创建自定义Asset类)

此时如果新建一个正确Actor 蓝图,会发现覆盖了原来的资产并正确打开蓝图。在报错的地方打断点,重新编译来看看如果新建正确的Actor 蓝图类,会不会走到这里。
答案是不会!没有进入check之前的if判断!所以自定义的资源也不能继承于Actor。下面为部分关于报错的check的源码

FSelectedActorInfo BuildSelectedActorInfo( const TArray<AActor*>& SelectedActors)
{
	//...
	// 正确的Actor蓝图过程连这个if都没进去
	if( FirstActor && !FirstActor->IsTemplate() )
	{
		//...
		if( ActorInfo.bAllSelectedActorsBelongToSameWorld )
		{
			//...
			if ( !ActorInfo.SharedWorld )
			{
				ActorInfo.SharedWorld = CurrentActor->GetWorld();
				check(ActorInfo.SharedWorld);
			}
			//...
		}
		//...
	}
	//...
}

个人总结

已知Actor 类能产生蓝图类资产。在用插件创建自定义的资源时,要清楚创建的是实例!而不是类,在判断为实例后,就会判断actor所属的World,但是Actor所属的World为空,这就出现一系列问题了。
所以 Actor的实例应该是放在关卡中的,序列化进相关的asset中,无法剥离出来单独存在于asset中。文章来源地址https://www.toymoban.com/news/detail-438733.html

到了这里,关于UE4 c++保存asset实例(含创建自定义Asset类)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • UE4动作游戏实例RPG Action解析一:角色移动,旋转,动画创建,创建武器,及武器配置

    UE4动作游戏实例RPG Action解析一:角色移动,旋转,动画创建,创建武器,及武器配置

    1.1、官方RPGAction Demo下载地址: ​ 1.2、在场景中创建一个空的角色 创建一个Character蓝图和一个PlayerController蓝图,添加弹簧臂组件和摄像机,并为网格体添加上一个骨骼网格体 ​ 1.3、如何让这个角色出现在场景中, 创建一个GameMode蓝图,把默认Pawn类设置成我们创建的角色,

    2024年02月03日
    浏览(60)
  • ue4中使用c++实现自定义网格体

    ue4中使用c++实现自定义网格体

    有两个类可以在ue4中实现自定义网格体,分别是UCustomMeshComponent和UProceduralMeshComponent,实现的方法都是构建三角形以实现不同的网格体。 网上的教程以蓝图为主,但我想用c++实现。 我找到了一篇用UProceduralMeshComponent实现的博客,链接如下:https://blog.csdn.net/yb0022/article/details

    2024年02月07日
    浏览(11)
  • UE4 C++:Actor与Component的创建、销毁

    目录 Actor的创建与销毁 创建 UClass* TSubclassOf SpawnActor() 销毁 直接销毁:Destroy() 设置生命周期 Component 的创建与销毁 创建 构造函数创建:CreateDefaultSubobject Runtime创建:NewObject、RegisterComponent() 加载资源 FObjectFinder构造函数加载资源 LoadObject加载资源 设置组件层级关系 销毁组件

    2023年04月11日
    浏览(11)
  • iOS提审报错Asset validation failed(90087),Asset validation failed (90125)

    问题:iOS提审时被苹果打回,打回原因如下: Asset validation failed (90125) The binary is invalid. The encryption info in the LC_ENCRYPTION_INFO load command is either missing or invalid, or the binary is already encrypted. This binary does not seem to have been built with Apple\\\'s linker.  Asset validat

    2024年02月11日
    浏览(11)
  • UE4中C++动态创建材质的几种方法Material

    第一种方式:         1、首先加载材质,代码如下: UMaterialInterface* Material = LoadObjectUMaterialInterface(nullptr, TEXT(\\\"Material\\\'/Game/Materials/ColorMaterial.ColorMaterial\\\'\\\"));         2、然后调用CreateDynamicMaterialInstance创建静态材质实例,如下: UMaterialInstance * DynamicMaterial = UKismetMaterialLibr

    2024年02月08日
    浏览(8)
  • Unity——资产包(Asset Bundles)

    Unity——资产包(Asset Bundles)

    对很多单机游戏来说,游戏的所有资源往往是与游戏本体一同发布的,资源不需要独立出来。但对于大型商业项目来说,游戏产品还需要再发布之后进行维护和更新,这就引出了Unity资产包的概念 其实一般来说,只要把资源放在合适的文件夹下,Unity就会妥善处理。但是,对

    2024年02月05日
    浏览(9)
  • WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).

    WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).

    vue项目打包 报warning: asset size limit: The following asset(s) exceed the recommended size limit (244 KiB). This can impact web performance. 这个警告的原因是因为vue的引入的js文件太大 解决方案:可以放开VUE打包大小限制 在vue项目中的vue.config.js的configureWebpack添加如下代码 最后再重新打包一下就好了

    2024年02月03日
    浏览(10)
  • ue4/5蓝图与c++混用基础入门的基础操作(适合有蓝图基础和c++基础的新手,创建自己的蓝图)

    ue4/5蓝图与c++混用基础入门的基础操作(适合有蓝图基础和c++基础的新手,创建自己的蓝图)

            首先是最开始的创建项目,用c++模式进行创建。         ue4:         ue5:  创建之后,两个都会自动为你打开vs,不过ue4.26要的是vs2019,ue5要的是vs2022,有时候打不开是缺少一些东西,这些东西在csdn里面可以查到,作者就不细讲了。 在ue5(4是一样的)中,我们可

    2023年04月12日
    浏览(35)
  • UE4游戏保存

    UE4游戏保存

    在游戏运行过程中由于某些事情需要暂停一下游戏,那就需要把游戏当前的进度保存起来,下次打开的时候还可以再次玩,我们这里主要保存的就是。所有需要有一个游戏保存的机制。UE4提供了这样的机制。 首先新建一个类继承在SaveGame,命名为FirstSaveGame 打开VS2019编辑代码

    2024年02月12日
    浏览(69)
  • unity stuck on initialize asset database

    unity stuck on initialize asset database

    unity开启项目一直停留在initialize asset database refresh 我目前尝试了一个方法,解决了这个问题,大家不妨可以试一试。 -DisableDirectoryMonitor 重启在启动。

    2024年02月04日
    浏览(8)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包