2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[UE4] AssetTypeをつくる

Last updated at Posted at 2021-08-29

コンテンツアセットタイプとはテクスチャやスタティックメッシュなど、エディタ上で作成できるオブジェクトで、必ずしもレベルに配置せずともよく、エディター内で静的なインスタンスをつくることができるというものです。

Animation.gif

ここでは、独自のコンテンツアセットタイプを作成する最小構成のみの手順だけまとめます。Pluginとして実装する前提ですが、プロジェクト内でも同様のはずです。
本記事は、Gerke Max Preussner氏の Adding New Asset Types to UE4 を参考にしています。実際のコードも氏のGithubレポを参考にするとより実用の理解が進むはずです。

執筆時のバージョンは 4.27.0 です。

1. RuntimeモジュールとEditorモジュールを用意する

Runtimeモジュールに加えてEditorモジュールも用意します。モジュールを分けなくても動作しますが、慣例に従いEditorモジュールを作成したほうが良いでしょう。配布時の容量や動作の効率性など恩恵が多いはずです。

最初に、Plugins > New Plugin から空のプラグイン(ここでは便宜上 "TestPlugin" と命名)を作成します。

newplugin.png

エクスプローラー上でプラグインモジュール( Plugins / TestPlugin / Source 配下のディレクトリ)をコピペしつつ、設定ファイルやビルドスクリプトを書き換えます。

/TestPlugin
  ...
  /Source
    /TestPlugin
      /Private
        TestPlugin.cpp
      /Public
        TestPlugin.cpp
      TestPlugin.Build.cs
    /TestPluginEditor         <---- TestPluginをコピペしてディレクトリ名とファイル名をリネーム
      /Private
        TestPluginEditor.cpp
      /Public
        TestPluginEditor.h
      TestPlugin.Build.cs
  TestPlugin.uplugin

.upluginファイルのモジュールにEditorモジュールを追加します。

TestPlugin.uplugin
{
	...
	"Modules" :
	[
		{
			"Name" : "TestPlugin",
			"Type" : "Runtime",
			"LoadingPhase" : "Default"
		},
		{
			"Name" : "TestPluginEditor",
			"Type" : "Editor",
			"LoadingPhase" : "Default"
		}
	]
}
Source/TestPlugin/TestPlugin.Build.cs
namespace UnrealBuildTool.Rules
{
	public class TestPlugin : ModuleRules
	{
		public TestPlugin(ReadOnlyTargetRules Target) : base(Target)
		{
			PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

			PublicDependencyModuleNames.AddRange(
				new string[] {
					"Core",
					"CoreUObject",
				});
		}
	}
}

Editorモジュール用のビルドスクリプトのネームスペースやクラス名、依存先を書き換えます。TestPluginTestPluginEditorと書き換えます。

Source/TestPluginEditor/TestPluginEditor.Build.cs
using UnrealBuildTool;

public class TestPluginEditor : ModuleRules
{
	public TestPluginEditor(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"Core",
				"CoreUObject",
				"TestPlugin", // アセットを定義するRuntimeモジュールを依存先に追加
				"UnrealEd", // Editor用のモジュールを依存先に追加
			});
	}
}

デフォルトで配置されているモジュール自体の定義クラスもリネームしておきます。TestPluginTestPluginEditorと書き換えます。

Source/TestPluginEditor/Public/TestPluginEditor.h
#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class FTestPluginEditorModule : public IModuleInterface
{
public:

	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};
Source/TestPluginEditor/Private/TestPluginEditor.cpp
#include "TestPluginEditor.h"
#define LOCTEXT_NAMESPACE "FMTestluginEditorModule"

void FTestPluginEditorModule::StartupModule()
{}

void FTestPluginEditorModule::ShutdownModule()
{}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FTestPluginEditorModule, TestPluginEditor)

2. UObject派生のクラスを定義する

AssetTypeとなる UObject 派生クラスを、Runtimeモジュール配下に、Publicとして定義します。

image.png

パラメータは任意です。確認用に複数作って置くと良いでしょう。

Source/TestPlugin/Public/UserDefinedObject.h
#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "UserDefinedAsset.generated.h"

UCLASS(BlueprintType)
class TESTPLUGIN_API UUserDefinedAsset : public UObject
{
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere)
	int32 IntParam;

	UPROPERTY(EditAnywhere)
	FText TextParam;
};

この時点でビルドしてみると、C++クラスはつくられていることが確認できますが、AssetTypeとしてエディター内インスタンスを作成することはできません。

image.png

3. AssetFactoryクラスを実装する

UFactoryを継承するオブジェクトをEditorモジュール配下にPrivateで実装します。
ファクトリとは、インスタンス生成時の処理をテンプレートをもとにして切り分けることで、柔軟なクラス定義を可能にするというデザインパターンに則った概念です。つまり、当該アセットのインスタンス生成時の振る舞いをお作法に則って定義するということです。

Source/TestPluginEditor/Private/UserDefinedAssetFactory.h
#pragma once

#include "CoreMinimal.h"
#include "Factories/Factory.h"
#include "UserDefinedAssetFactory.generated.h"

UCLASS()
class UUserDefinedAssetFactory : public UFactory
{
	GENERATED_UCLASS_BODY()

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

ファクトリの実装内容としては、

  • コンストラクター内でメンバー変数であるSupportedClassに、先程作ったUObject派生クラスのStaticClassを代入します。
  • FactoryCreateNew関数をオーバーライドして、先程作ったUObject派生クラスのインスタンスを返すようにします。
  • ShouldShowInMenuをオーバーライドして、Trueを返すようにすることで、アセットメニューの表示を許可します。
Source/TestPluginEditor/Private/UserDefinedAssetFactory.cpp
#include "UserDefinedAssetFactory.h"
#include "UserDefinedAsset.h"

UUserDefinedAssetFactory::UUserDefinedAssetFactory(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	SupportedClass = UUserDefinedAsset::StaticClass();
	bCreateNew = true;
	bEditAfterNew = true;
}

UObject* UUserDefinedAssetFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
	return NewObject<UUserDefinedAsset>(InParent, InClass, InName, Flags);
}

bool UUserDefinedAssetFactory::ShouldShowInNewMenu() const
{
    return true;
}

これでもまだアセットタイプの実装は完了していません。

4. AssetTypeActionsをつくり、登録する

FAssetTypeActions_Baseを継承するクラスをオブジェクトを作成します。エディター内でインスタンス生成される際のエディターの挙動をより具体的に定義することができます。
エディター内インスタンスのアイコンや色、アセットタイプのカテゴリーなどを指定します。

OpenAssetEditorGetActionsといった関数をコメントアウトしていますが、これらをオーバーライドすると、アセットエディターのインターフェースや、ファイルをドラッグするインスタンス生成など高度な定義ができますが、非常に長くなりそうなので今回はそれらを扱いません。代わりに、デフォルトの(スーパークラス)の関数をそのまま使います。

Source/TestPluginEditor/Private/TestPluginActions.h
#pragma once

#include "AssetTypeActions_Base.h"

class FTestPluginActions : public FAssetTypeActions_Base
{
public:

	virtual FText GetName() const override;
	virtual FColor GetTypeColor() const override;
	virtual UClass* GetSupportedClass() const override;
	virtual uint32 GetCategories() override;

	//virtual void OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor = TSharedPtr<IToolkitHost>()) override;
	//virtual void GetActions(const TArray<UObject*>&InObjects, FMenuBuilder & MenuBuilder) override;
	//virtual bool HasActions(const TArray<UObject*>& InObjects) const override;

private:
};

ここでは、

  • AssetActionの名称と、適用対象のクラス(UUserDefinedAsset)を設定
  • アセットタイプのアイコンの色を白
  • カテゴリーはMedia配下

としています。

Source/TestPluginEditor/Private/TestPluginActions.cpp
#include "TestPluginActions.h"
#include "UserDefinedAsset.h"

FText FTestPluginActions::GetName() const
{
	return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_TestPlugin", "Test Plugin");
}

FColor FTestPluginActions::GetTypeColor() const
{
	return FColor::White;
}

UClass* FTestPluginActions::GetSupportedClass() const
{
	return UUserDefinedAsset::StaticClass();
}

uint32 FTestPluginActions::GetCategories()
{
	return EAssetTypeCategories::Media;
}

最後にAssetTypeActionsを登録します。UFactoryなどUObject派生クラスのエンジンへの登録は暗黙的におこなれますが、それ以外は、明示的にコードを書かないといけなかったりする罠があったりします。AssetTypeActionsAssetToolsに登録してあげる必要があるので、モジュールの定義クラスにコードを追加します。

Source/TestPluginEditor/Public/TestPluginEditor.h
#include "TestPluginEditor.h"
#include "Modules/ModuleInterface.h"
#include "TestPluginActions.h"

#define LOCTEXT_NAMESPACE "FTestPluginEditorModule"

void FTestPluginEditorModule::StartupModule()
{
	IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
	AssetTools.RegisterAssetTypeActions(MakeShareable(new FTestPluginActions()));
}

void FTestPluginEditorModule::ShutdownModule()
{}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FTestPluginEditorModule, TestPluginEditor)

以上で、最小構成でのアセットタイプの作成が完了しました。

Animation.gif

AssetTypeActionsOpenAssetEditorをオーバーライドをしていないので、デフォルト表示のアセットエディタが開かれます。アセットエディタのカスタマイズ自体はまた別に扱いたいと思います。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?