此文章,主要是为了记录,在开发模式的插件(无图标)中,遇到的一些问题,调用堆栈过程中查看的函数层级关系。模式这块的坑是比较大的,从模式的注册、激活、保存关卡后模式的激活状态、新建关卡后模式的激活状态、切换关卡后模式的激活状态等各种各样的情况。那么接下来会从模式的注册与激活两方面来阐述,其他的情况视每个人的开发功能背景而定。

1. 注册Mode
Engine\Source\Editor\UnrealEd\Public\EditorModeRegistry.h
/**
* 编辑器模式和工厂注册表
*/
class FEditorModeRegistry
来看看具体的注册函数
void FEditorModeRegistry::RegisterMode(FEditorModeID ModeID, TSharedRef<IEditorModeFactory> Factory)
{
check(ModeID != FBuiltinEditorModes::EM_None);
check(!ModeFactories.Contains(ModeID));
ModeFactories.Add(ModeID, Factory);
OnModeRegisteredEvent.Broadcast(ModeID);
RegisteredModesChanged.Broadcast();
}
其中主要的关键点在于 往 ModeFactories 添加 模式的ID 和 工厂信息, 这里留一个彩蛋, 因为这个Map类型, 我们在激活模式的时候也会使用到.
注意:一般注册模式会放在模块的 StartupModule() 中。
需要注意的是注册自定义的Mode的时间节点不一定就会比UE本身的Mode注册的时间结点晚;毕竟我刚开始认为,我自己定义的模式,注册总在UE本身的Mode注册之后,后来打断点调用堆栈瞅了瞅,原来是自己错了。
2. 激活Mode
说到激活Mode,不得不说一个UE中强大的基础头文件,那就是Editor.h,为什么说它呢?见下函数
Engine\Source\Editor\UnrealEd\Public\Editor.h
/**
* 提供对关卡编辑器的FEditorModeTools的访问
*/
UNREALED_API class FEditorModeTools& GLevelEditorModeTools();
GLevelEditorModeTools()函数 new了一个FEditorModeTools 对象,并且将创建的对象作为返回值返回。那么这个FEditorModeTools类又可以干什么呢?来看看它的定义:
Engine\Source\Editor\UnrealEd\Public\EditorModeManager.h
/**
* 一个帮助程序类,用于存储各种编辑器模式的状态
*/
class UNREALED_API FEditorModeTools : public FGCObject, public FEditorUndoClient
一起看看在这个FEditorModeTools类中,有哪些函数
/*激活编辑器模式*/
void ActivateMode( FEditorModeID InID, bool bToggle = false );
/*禁用编辑器模式*/
void DeactivateMode(FEditorModeID InID);
/*如果传入的编辑器模式处于活动状态,则返回true*/
bool IsModeActive( FEditorModeID InID ) const;
再来看看类中有哪些属性
/**活动编辑器模式的列表*/
TArray< TSharedPtr<FEdMode> > ActiveModes;
/**我们可能会回收的先前活动的编辑器模式列表*/
TMap< FEditorModeID, TSharedPtr<FEdMode> > RecycledModes;
看到这些成员函数和成员属性, 顾名思义,这个类的功能有: 模式的激活、模式的禁用、判断模式是否被激活、激活模式的列表、激活模式的回收等等。
废话说了这么多,目的就是为了要说,在UE中,一般都是通过下面的方式去激活模式的:
GLevelEditorModeTools().ActivateMode(FEditorModeID);
下面就聊聊激活的两种方式
(1)点击图标激活

对于点击图标而言,必定是要有图标的,也就是说在模式那块,存在自己定义的模式图标,如上图所示,那么就需要注册一个有图标的模式,在注册的时候,传入 FSlateIcon 等参数 ,即可:
具体方法如下:
FEditorModeRegistry::Get().RegisterMode<自定义的Mode类名>(FEditorModeID, LOCTEXT(" ", " "), FSlateIcon(), true);
点击图标激活的话,会经过 点击 Click事件,然后激活点击的模式。具体调用层级结构如下:

(2)手动激活

对于手动激活而言,必定是没有图标的,也就是说在模式那块,没有自己定义的模式图标,如上图所示。那么如何去注册一个没有图标的模式呢?在注册的时候,直接省略 FSlateIcon 等参数,使用注册函数的默认参数。具体方法如下:

FEditorModeRegistry::Get().RegisterMode<自定义的Mode类名>(FEditorModeID);
手动激活的话,就返回到刚刚在第二点中说的,在 Editor.h 中的 GLevelEditorModeTools()函数 返回类型 FEditorModeTools 的 ActivateMode 函数,在想要激活的位置,去手动调用一下这个函数即可。例如:
GLevelEditorModeTools().ActivateMode(FEditorModeID);
这两种激活的方式,其实都会调用到FEditorModeTools 的 ActiveMode函数。
那就来看看 ,这个函数里到底有多少料吧,当然我不会把函数体全部搬过来,只说我认为的一些关键代码



- ①是否是前面激活的回收模式,主要是为了 从A模式切换到B模式做准备
- ②开篇说的彩蛋 Map,主要是判断此模式是否是已经注册过的
- ③bool值判断 共同存活,欲激活的模式是否与其他的模式共同存在
- ④ActiveModes 和 RecycledModes 的Add
- ⑤CreatMode 与 构造 还有 Enter 调用到了自定义模式的 构造函数 和 Enter函数
3. 多种模式共同激活
我们可以看到 在ActiveMode 函数中,调用了 具体Mode的 IsCompatibleWith() 这样的一个函数,查看这个函数的翻译,这个函数就是为了让多种模式共同存在而服务的。

Engine\Source\Editor\UnrealEd\Public\EdMode.h
virtual bool IsCompatibleWith(FEditorModeID OtherModeID) const { return false; }
如果想要共同存活,我们可以在继承类中,重写这个函数,返回 true即可。
网友评论