编辑器扩展:自定义PlaceActors
前言
有的时候, 为了方便项目需求, 我们需要自定义PlaceActors标签以及对应的类
本文记录如何实现这一扩展
自定义标签
开始之前我们需要了解一下UE4编辑器模块的启动顺序, 可以参考之前的一篇文章 UE4模块启动顺序
关键的一点是, 我们对编辑器添加新的PlaceActors标签需要在编辑器初始化之后, 因为IPlacementModeModule::Get()
会启动PlacementMode
模块, 而该模块启动时需要构造FPlaceableItem
对象, FPlaceableItem
对象构造时需要依赖GEditor->FindActorFactoryByClass()
函数, 该函数实现如下
1 | UActorFactory* UEditorEngine::FindActorFactoryByClass( const UClass* InClass ) const |
ActorFactories
数组会在UEditorEngine::InitEditor()
时完成, 意味着我们注册标签必须在编辑器初始化完成之后.
所以我们实现自定义PlaceActors标签的插件模块必须是PostEngineInit
, 或者我们还有一个更安全的办法, 即通过监听编辑器初始化完成的回调事件来实现
1 | FCoreDelegates::OnPostEngineInit.AddRaw(this, &FAdvancedFrameworkEditorModule::RegisterPlaceActors); |
1 | void FAdvancedFrameworkEditorModule::RegisterPlaceActors() |
这里我们先添加一个叫AdvancedFrameworkActors
的标签, 然后使用引擎默认的EmptyActor
来先添加一个对象
先看一下数据结构FPlacementCategoryInfo
1 | struct FPlacementCategoryInfo |
我们显示的名称是构造函数的第二个字符串, 然后第4个参数决定我们的排序优先级, 我们打算放到最下面所以设置成了99
添加对象
接下来要看的是RegisterPlaceableItem()
1 | TOptional<FPlacementModeID> FPlacementModeModule::RegisterPlaceableItem(FName CategoryName, const TSharedRef<FPlaceableItem>& InItem) |
需要传入一个FPlaceableItem
对象, 再来看FPlaceableItem
的构造函数
1 | FPlaceableItem(UActorFactory* InFactory, const FAssetData& InAssetData, TOptional<int32> InSortOrder = TOptional<int32>()); |
理论上讲上述构造函数都可以使用, 但是我们本着能方便就方便, 能偷懒就偷懒的原则, 先去看一看引擎自己咋使用的
1 | //PlacementModeModule.cpp L123 |
看上述代码, 所以引擎自己都使用一个UActorFactory
对象, 观察这个类
1 |
|
看了一些引擎的实现, 重点就是上面这些成员变量, 以及部分虚函数的实现, 比如
1 | virtual bool CanCreateActorFrom( const FAssetData& AssetData, FText& OutErrorMsg ); |
其实一些类比如骨骼模型SkeletalMesh, 直接拖拽到编辑器世界空间中他会创建一个Actor来完成骨骼模型的显示, 而我们其实可以不需要这一步骤(如果我们的对象本身就是一个普通的actor)
所以可以这样添加
1 | IPlacementModeModule::Get().RegisterPlaceableItem(MyCategoryInfo.UniqueHandle, MakeShareable(new FPlaceableItem(nullptr, FAssetData(XXX:StaticClass())))); |
我这边在项目设置里丢进去一个数组TArray<TSubclassOf<AActor>> PlacementActors;
那就可以动态的扩展这一个标签下的显示对象
1 | if(UAF_GameSetting_Default* st = UAF_BlueprintLibrary::GetDefaultSetting()) |
最后实现效果如下