此文章感凤,主要是為了記錄,在開發(fā)模式的插件(無圖標(biāo))中粒督,遇到的一些問題陪竿,調(diào)用堆棧過程中查看的函數(shù)層級(jí)關(guān)系。模式這塊的坑是比較大的屠橄,從模式的注冊(cè)族跛、激活、保存關(guān)卡后模式的激活狀態(tài)锐墙、新建關(guān)卡后模式的激活狀態(tài)礁哄、切換關(guān)卡后模式的激活狀態(tài)等各種各樣的情況。那么接下來會(huì)從模式的注冊(cè)與激活兩方面來闡述贮匕,其他的情況視每個(gè)人的開發(fā)功能背景而定姐仅。
1. 注冊(cè)Mode
Engine\Source\Editor\UnrealEd\Public\EditorModeRegistry.h
/**
* 編輯器模式和工廠注冊(cè)表
*/
class FEditorModeRegistry
來看看具體的注冊(cè)函數(shù)
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();
}
其中主要的關(guān)鍵點(diǎn)在于 往 ModeFactories 添加 模式的ID 和 工廠信息, 這里留一個(gè)彩蛋, 因?yàn)檫@個(gè)Map類型, 我們?cè)诩せ钅J降臅r(shí)候也會(huì)使用到.
注意:一般注冊(cè)模式會(huì)放在模塊的 StartupModule() 中。
需要注意的是注冊(cè)自定義的Mode的時(shí)間節(jié)點(diǎn)不一定就會(huì)比UE本身的Mode注冊(cè)的時(shí)間結(jié)點(diǎn)晚刻盐;畢竟我剛開始認(rèn)為掏膏,我自己定義的模式,注冊(cè)總在UE本身的Mode注冊(cè)之后敦锌,后來打斷點(diǎn)調(diào)用堆棧瞅了瞅馒疹,原來是自己錯(cuò)了。
2. 激活Mode
說到激活Mode乙墙,不得不說一個(gè)UE中強(qiáng)大的基礎(chǔ)頭文件颖变,那就是Editor.h,為什么說它呢听想?見下函數(shù)
Engine\Source\Editor\UnrealEd\Public\Editor.h
/**
* 提供對(duì)關(guān)卡編輯器的FEditorModeTools的訪問
*/
UNREALED_API class FEditorModeTools& GLevelEditorModeTools();
GLevelEditorModeTools()函數(shù) new了一個(gè)FEditorModeTools 對(duì)象腥刹,并且將創(chuàng)建的對(duì)象作為返回值返回。那么這個(gè)FEditorModeTools類又可以干什么呢汉买?來看看它的定義:
Engine\Source\Editor\UnrealEd\Public\EditorModeManager.h
/**
* 一個(gè)幫助程序類衔峰,用于存儲(chǔ)各種編輯器模式的狀態(tài)
*/
class UNREALED_API FEditorModeTools : public FGCObject, public FEditorUndoClient
一起看看在這個(gè)FEditorModeTools類中,有哪些函數(shù)
/*激活編輯器模式*/
void ActivateMode( FEditorModeID InID, bool bToggle = false );
/*禁用編輯器模式*/
void DeactivateMode(FEditorModeID InID);
/*如果傳入的編輯器模式處于活動(dòng)狀態(tài)蛙粘,則返回true*/
bool IsModeActive( FEditorModeID InID ) const;
再來看看類中有哪些屬性
/**活動(dòng)編輯器模式的列表*/
TArray< TSharedPtr<FEdMode> > ActiveModes;
/**我們可能會(huì)回收的先前活動(dòng)的編輯器模式列表*/
TMap< FEditorModeID, TSharedPtr<FEdMode> > RecycledModes;
看到這些成員函數(shù)和成員屬性, 顧名思義,這個(gè)類的功能有: 模式的激活垫卤、模式的禁用、判斷模式是否被激活出牧、激活模式的列表穴肘、激活模式的回收等等。
廢話說了這么多舔痕,目的就是為了要說评抚,在UE中豹缀,一般都是通過下面的方式去激活模式的:
GLevelEditorModeTools().ActivateMode(FEditorModeID);
下面就聊聊激活的兩種方式
(1)點(diǎn)擊圖標(biāo)激活
對(duì)于點(diǎn)擊圖標(biāo)而言,必定是要有圖標(biāo)的慨代,也就是說在模式那塊耿眉,存在自己定義的模式圖標(biāo),如上圖所示鱼响,那么就需要注冊(cè)一個(gè)有圖標(biāo)的模式,在注冊(cè)的時(shí)候组底,傳入 FSlateIcon 等參數(shù) 丈积,即可:
具體方法如下:
FEditorModeRegistry::Get().RegisterMode<自定義的Mode類名>(FEditorModeID, LOCTEXT(" ", " "), FSlateIcon(), true);
點(diǎn)擊圖標(biāo)激活的話,會(huì)經(jīng)過 點(diǎn)擊 Click事件债鸡,然后激活點(diǎn)擊的模式江滨。具體調(diào)用層級(jí)結(jié)構(gòu)如下:
(2)手動(dòng)激活
對(duì)于手動(dòng)激活而言,必定是沒有圖標(biāo)的厌均,也就是說在模式那塊唬滑,沒有自己定義的模式圖標(biāo),如上圖所示棺弊。那么如何去注冊(cè)一個(gè)沒有圖標(biāo)的模式呢晶密?在注冊(cè)的時(shí)候财松,直接省略 FSlateIcon 等參數(shù)邑时,使用注冊(cè)函數(shù)的默認(rèn)參數(shù)。具體方法如下:
FEditorModeRegistry::Get().RegisterMode<自定義的Mode類名>(FEditorModeID);
手動(dòng)激活的話锋边,就返回到剛剛在第二點(diǎn)中說的侈净,在 Editor.h 中的 GLevelEditorModeTools()函數(shù) 返回類型 FEditorModeTools 的 ActivateMode 函數(shù)尊勿,在想要激活的位置,去手動(dòng)調(diào)用一下這個(gè)函數(shù)即可畜侦。例如:
GLevelEditorModeTools().ActivateMode(FEditorModeID);
這兩種激活的方式元扔,其實(shí)都會(huì)調(diào)用到FEditorModeTools 的 ActiveMode函數(shù)。
那就來看看 旋膳,這個(gè)函數(shù)里到底有多少料吧澎语,當(dāng)然我不會(huì)把函數(shù)體全部搬過來,只說我認(rèn)為的一些關(guān)鍵代碼
- ①是否是前面激活的回收模式溺忧,主要是為了 從A模式切換到B模式做準(zhǔn)備
- ②開篇說的彩蛋 Map咏连,主要是判斷此模式是否是已經(jīng)注冊(cè)過的
- ③bool值判斷 共同存活,欲激活的模式是否與其他的模式共同存在
- ④ActiveModes 和 RecycledModes 的Add
- ⑤CreatMode 與 構(gòu)造 還有 Enter 調(diào)用到了自定義模式的 構(gòu)造函數(shù) 和 Enter函數(shù)
3. 多種模式共同激活
我們可以看到 在ActiveMode 函數(shù)中鲁森,調(diào)用了 具體Mode的 IsCompatibleWith() 這樣的一個(gè)函數(shù)祟滴,查看這個(gè)函數(shù)的翻譯,這個(gè)函數(shù)就是為了讓多種模式共同存在而服務(wù)的歌溉。
Engine\Source\Editor\UnrealEd\Public\EdMode.h
virtual bool IsCompatibleWith(FEditorModeID OtherModeID) const { return false; }
如果想要共同存活垄懂,我們可以在繼承類中骑晶,重寫這個(gè)函數(shù),返回 true即可草慧。