一、插件分類
插件分為七大類
- Blank:空白插件,可以從頭開始自己定義想要的插件風(fēng)格和內(nèi)容,用此模板創(chuàng)建的插件不會有注冊或者菜單輸入。
- BlueprintLibrary:創(chuàng)建一個含有藍圖函數(shù)庫的插件,此模板函數(shù)都是靜態(tài)全局函數(shù),可以在藍圖中直接調(diào)用。
- ContentOnly:創(chuàng)建一個只包含內(nèi)容的空白文件
- Editor Toolbar Button:創(chuàng)建關(guān)卡編輯器的工具欄中的按鈕插件,首先在創(chuàng)建的點擊事件中實現(xiàn)一些內(nèi)容
- Editor Standalone Window:創(chuàng)建關(guān)卡編輯器的工具欄中的按鈕插件,點擊按鈕可調(diào)出一個空白選項獨立卡窗口
- Editor Mode:創(chuàng)建一個含有編輯器模式的插件
- Third Party Library:創(chuàng)建一個已包含第三方庫的插件
二、插件模塊?
插件可含有任意數(shù)量的模塊源目錄。多數(shù)插件僅有一個模塊(但可創(chuàng)建多個模塊,例如插件包含純編輯器功能時),及游戲期間要運行的其他代碼。
插件源文件的大部分布局與引擎中其他C++模塊相同。
在模塊的?Source
?目錄(或其子目錄)內(nèi),插件可在標頭文件中聲明新反映的類型(UCLASS
、USTRUCT
?等)。引擎的構(gòu)建系統(tǒng)將檢測此類文件,并按需要生成代碼支持新類型。需遵守C++模塊中使用?Uobjects
?時的一般規(guī)則,例如在模塊的源文件中包含生成的標頭文件和模塊?generated.inl
?文件。
UE4支持共生模塊和插件。通過在自身.uproject文件中啟用插件,項目模塊可依賴插件。類似地,通過在自身.uplugin文件中啟用其他插件,插件可表明依賴性。但其中有一項重要限制:插件和模塊將拆分為若干層級,僅能依賴同一級或更高級的其他插件或模塊。例如,項目模塊可依賴引擎模塊,但引擎模塊無法依賴項目模塊。這是因為引擎(及其所有插件和模塊)的級別高于項目,須能在無項目的情況下編譯。
三、引擎插件和項目插件
虛幻引擎4的?Engine
?目錄下包含部分內(nèi)置插件。引擎插件和項目插件類似,但可用于所有項目。此類插件通常由引擎和工具程序員創(chuàng)建,目的在于提供可在多個項目中使用并能在單一位置維護的基線功能。利用此功能,用戶可直接添加或覆蓋引擎功能,而無需修改引擎代碼。
項目插件位于項目目錄的?Plugins
?子文件夾下,將在引擎或編輯器啟動時被探測和加載。如插件包含具有?Source
?文件夾(和?.Build.cs
?文件)的模塊,插件代碼將被自動添加到生成的C++項目文件,以便在開發(fā)項目時開發(fā)插件。編譯項目時,有可用源的插件都被作為游戲依賴項進行編譯。項目生成器將忽略無?Source
?文件夾的插件,其不會出現(xiàn)在C++項目文件中,但若存在二進制文件,啟動時仍將加載此類插件。
插件的描述,描述的文件是Json格式,以官方案例為準
{
"FileVersion" :3,
"Version" :1,
"VersionName" :"1.0",
"FriendlyName" :"UObject Example Plugin",
"Description" :"An example of a plugin which declares its own UObject type.This can be used as a starting point when creating your own plugin.",
"Category" :"Examples",
"CreatedBy" :"Epic Games, Inc.",
"CreatedByURL" :"http://epicgames.com",
"DocsURL" :"",
"MarketplaceURL" :"",
"SupportURL" :"",
"EnabledByDefault" : true,
"CanContainContent" : false,
"IsBetaVersion" : false,
"Installed" : false,
"Modules" :
[
{
"Name" :"UObjectPlugin",
"Type" :"Developer",
"LoadingPhase" :"Default"
}
]
}
?四、案例分析Editor Standalone Window
? 創(chuàng)建一個Editor Standalone Window插件,命名為:MyEditorStandaloneWindow
創(chuàng)建成功之后VS會出現(xiàn)Plugins
?出現(xiàn)三個cpp文件
MyEditorStandaloneWindow:主函數(shù)所有的主要邏輯都是寫在這里,包含了注冊命令,布局分布,按鈕點擊事件等。
MyEditorStandaloneWindowCommand:聲明一些命令變量,注冊函數(shù)等。
MyEditorStandaloneWindowStyle:插件的樣式風(fēng)格。
創(chuàng)建好之后我們會在編輯器工具欄中看到我們的插件
?點擊這個按鈕觸發(fā)的事件通過MapAction創(chuàng)建代理函數(shù)綁定,執(zhí)行
?創(chuàng)建獨立窗口
void FMyEditorStandaloneWindowModule::PluginButtonClicked()
{
FGlobalTabmanager::Get()->TryInvokeTab(MyEditorStandaloneWindowTabName);
}
?內(nèi)容的注冊通過FGlobalTabmanager::Get()->RegisterNomadTabSpawner
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(MyEditorStandaloneWindowTabName, FOnSpawnTab::CreateRaw(this, &FMyEditorStandaloneWindowModule::OnSpawnPluginTab))
.SetDisplayName(LOCTEXT("FMyEditorStandaloneWindowTabTitle", "MyEditorStandaloneWindow"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
他本質(zhì)上就是一個SDockTab,返回的是一個TSharedRef<SDockTab>的引用,
TSharedRef<SDockTab> FMyEditorStandaloneWindowModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
FText WidgetText = FText::Format(
LOCTEXT("WindowWidgetText", "Add code to {0} in {1} to override this window's contents"),
FText::FromString(TEXT("FMyEditorStandaloneWindowModule::OnSpawnPluginTab")),
FText::FromString(TEXT("MyEditorStandaloneWindow.cpp"))
);
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
// Put your tab content here!
SNew(SBox)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(WidgetText)
]
];
}
五、自定義插件內(nèi)容?
首先打開UI擴展點
這些綠色的擴展點主要是用于菜單按鈕和工具按鈕的排序的,添加一個綠色的擴展點統(tǒng)管N個菜單按鈕,如果你可以自定義自己的UI擴展點,并將自己的擴展點下的菜單按鈕安插在某個擴展點之后。也就是UI擴展點是用于布局菜單欄和工具欄的順序的。
第一步:首先加載模塊
//首先加載模塊FExtend最后都在FLevelEditorModule中管理
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
第二步:創(chuàng)建對象
{
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
MenuExtender->AddMenuExtension("WindowLayout", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FMyEditorStandaloneWindowModule::AddMenuExtension));
LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
}
{
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
ToolbarExtender->AddToolBarExtension("Settings", EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FMyEditorStandaloneWindowModule::AddToolbarExtension));
LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
}
?第三步:注冊綁定對象事件
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(MyEditorStandaloneWindowTabName, FOnSpawnTab::CreateRaw(this, &FMyEditorStandaloneWindowModule::OnSpawnPluginTab))
.SetDisplayName(LOCTEXT("FMyEditorStandaloneWindowTabTitle", "MyTestWindow"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
FGlobalTabmanager::Get()->RegisterNomadTabSpawner("MyWindow1", FOnSpawnTab::CreateRaw(this, &FMyEditorStandaloneWindowModule::SpawnCustomTab))
.SetDisplayName(LOCTEXT("FMyEditorStandaloneWindowTabTitle", "MyWindow1"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
FGlobalTabmanager::Get()->RegisterNomadTabSpawner("MyWindow2", FOnSpawnTab::CreateRaw(this, &FMyEditorStandaloneWindowModule::SpawnCustomTab))
.SetDisplayName(LOCTEXT("FMyEditorStandaloneWindowTabTitle", "MyWindow2"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
第四步:FTabManager重新布局
const TSharedRef<SDockTab> NomadTab = SNew(SDockTab)
.TabRole(ETabRole::NomadTab);
if (!MyWindowTabManager.IsValid())
{
MyWindowTabManager = FGlobalTabmanager::Get()->NewTabManager(NomadTab);
}
if (!MyWindowLayout.IsValid())
{
MyWindowLayout = FTabManager::NewLayout("TestLayoutWindow")
->AddArea
(
FTabManager::NewPrimaryArea()
->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(.5f)
->AddTab("MyWindow1", ETabState::OpenedTab)
)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(.5f)
->AddTab("MyWindow2", ETabState::OpenedTab)
)
);
}
TSharedRef<SWidget> TabContents = MyWindowTabManager->RestoreFrom(MyWindowLayout.ToSharedRef(), TSharedPtr<SWindow>()).ToSharedRef();
NomadTab->SetContent(TabContents);
?效果如下:
?完整代碼附上:
MyEditorStandaloneWindow.h文件文章來源:http://www.zghlxwxcb.cn/news/detail-449427.html
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FToolBarBuilder;
class FMenuBuilder;
class FMyEditorStandaloneWindowModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
/** This function will be bound to Command (by default it will bring up plugin window) */
void PluginButtonClicked();
private:
void RegisterMenus();
TSharedRef<class SDockTab> OnSpawnPluginTab(const class FSpawnTabArgs& SpawnTabArgs);
private:
TSharedPtr<class FUICommandList> PluginCommands;
void AddMenuExtension(FMenuBuilder& Builder);
void AddToolbarExtension(FToolBarBuilder& Builder);
TSharedRef<SDockTab> SpawnCustomTab(const FSpawnTabArgs& Arg);
TSharedPtr<FTabManager> MyWindowTabManager;
TSharedPtr<FTabManager::FLayout> MyWindowLayout;
};
MyEditorStandaloneWindow.cpp文件文章來源地址http://www.zghlxwxcb.cn/news/detail-449427.html
// Copyright Epic Games, Inc. All Rights Reserved.
#include "MyEditorStandaloneWindow.h"
#include "MyEditorStandaloneWindowStyle.h"
#include "MyEditorStandaloneWindowCommands.h"
#include "LevelEditor.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/Text/STextBlock.h"
#include "ToolMenus.h"
static const FName MyEditorStandaloneWindowTabName("MyEditorStandaloneWindow");
#define LOCTEXT_NAMESPACE "FMyEditorStandaloneWindowModule"
void FMyEditorStandaloneWindowModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
FMyEditorStandaloneWindowStyle::Initialize();
FMyEditorStandaloneWindowStyle::ReloadTextures();
FMyEditorStandaloneWindowCommands::Register();
PluginCommands = MakeShareable(new FUICommandList);
PluginCommands->MapAction(
FMyEditorStandaloneWindowCommands::Get().OpenPluginWindow,
FExecuteAction::CreateRaw(this, &FMyEditorStandaloneWindowModule::PluginButtonClicked),
FCanExecuteAction());
//UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FMyEditorStandaloneWindowModule::RegisterMenus));
//首先加載模塊FExtend最后都在FLevelEditorModule中管理
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
{
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
MenuExtender->AddMenuExtension("WindowLayout", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FMyEditorStandaloneWindowModule::AddMenuExtension));
LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
}
{
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
ToolbarExtender->AddToolBarExtension("Settings", EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FMyEditorStandaloneWindowModule::AddToolbarExtension));
LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
}
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(MyEditorStandaloneWindowTabName, FOnSpawnTab::CreateRaw(this, &FMyEditorStandaloneWindowModule::OnSpawnPluginTab))
.SetDisplayName(LOCTEXT("FMyEditorStandaloneWindowTabTitle", "MyTestWindow"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
FGlobalTabmanager::Get()->RegisterNomadTabSpawner("MyWindow1", FOnSpawnTab::CreateRaw(this, &FMyEditorStandaloneWindowModule::SpawnCustomTab))
.SetDisplayName(LOCTEXT("FMyEditorStandaloneWindowTabTitle", "MyWindow1"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
FGlobalTabmanager::Get()->RegisterNomadTabSpawner("MyWindow2", FOnSpawnTab::CreateRaw(this, &FMyEditorStandaloneWindowModule::SpawnCustomTab))
.SetDisplayName(LOCTEXT("FMyEditorStandaloneWindowTabTitle", "MyWindow2"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
}
void FMyEditorStandaloneWindowModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
UToolMenus::UnRegisterStartupCallback(this);
UToolMenus::UnregisterOwner(this);
FMyEditorStandaloneWindowStyle::Shutdown();
FMyEditorStandaloneWindowCommands::Unregister();
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(MyEditorStandaloneWindowTabName);
}
TSharedRef<SDockTab> FMyEditorStandaloneWindowModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
/*FText WidgetText = FText::Format(
LOCTEXT("WindowWidgetText", "Add code to {0} in {1} to override this window's contents"),
FText::FromString(TEXT("FMyEditorStandaloneWindowModule::OnSpawnPluginTab")),
FText::FromString(TEXT("MyEditorStandaloneWindow.cpp"))
);*/
//return SNew(SDockTab)
// .TabRole(ETabRole::NomadTab)
// [
// // Put your tab content here!
// SNew(SBox)
// .HAlign(HAlign_Center)
// .VAlign(VAlign_Center)
// [
// SNew(STextBlock)
// .Text(WidgetText)
// ]
// ];
const TSharedRef<SDockTab> NomadTab = SNew(SDockTab)
.TabRole(ETabRole::NomadTab);
if (!MyWindowTabManager.IsValid())
{
MyWindowTabManager = FGlobalTabmanager::Get()->NewTabManager(NomadTab);
}
if (!MyWindowLayout.IsValid())
{
MyWindowLayout = FTabManager::NewLayout("TestLayoutWindow")
->AddArea
(
FTabManager::NewPrimaryArea()
->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(.5f)
->AddTab("MyWindow1", ETabState::OpenedTab)
)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(.5f)
->AddTab("MyWindow2", ETabState::OpenedTab)
)
);
}
TSharedRef<SWidget> TabContents = MyWindowTabManager->RestoreFrom(MyWindowLayout.ToSharedRef(), TSharedPtr<SWindow>()).ToSharedRef();
NomadTab->SetContent(TabContents);
return NomadTab;
}
void FMyEditorStandaloneWindowModule::AddMenuExtension(FMenuBuilder& Builder)
{
Builder.AddMenuEntry(FMyEditorStandaloneWindowCommands::Get().OpenPluginWindow);
}
void FMyEditorStandaloneWindowModule::AddToolbarExtension(FToolBarBuilder& Builder)
{
Builder.AddToolBarButton(FMyEditorStandaloneWindowCommands::Get().OpenPluginWindow);
}
TSharedRef<SDockTab> FMyEditorStandaloneWindowModule::SpawnCustomTab(const FSpawnTabArgs& Arg)
{
return SNew(SDockTab);
}
void FMyEditorStandaloneWindowModule::PluginButtonClicked()
{
FGlobalTabmanager::Get()->TryInvokeTab(MyEditorStandaloneWindowTabName);
}
void FMyEditorStandaloneWindowModule::RegisterMenus()
{
// Owner will be used for cleanup in call to UToolMenus::UnregisterOwner
FToolMenuOwnerScoped OwnerScoped(this);
{
UToolMenu* Menu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Window");
{
FToolMenuSection& Section = Menu->FindOrAddSection("WindowLayout");
Section.AddMenuEntryWithCommandList(FMyEditorStandaloneWindowCommands::Get().OpenPluginWindow, PluginCommands);
}
}
{
UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar");
{
FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("Settings");
{
FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FMyEditorStandaloneWindowCommands::Get().OpenPluginWindow));
Entry.SetCommandList(PluginCommands);
}
}
}
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FMyEditorStandaloneWindowModule, MyEditorStandaloneWindow)
到了這里,關(guān)于【虛幻引擎】UE4/UE5插件的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!