[UE] Weapon Plugin 2: 버튼 만들기, 창 띄우기

어제 만든 기본세팅을 사용하여 Plugin 버튼을 만들어보자. 이번에 만들 Plugin 버튼은 Unreal Editor 상단에 Ribbon Button 형태로 만들어질 것이다. 오늘의 목표는 버튼을 만들어 창을 띄우기다.
목차
Plugins |
||||
Weapon |
||||
Resource |
||||
Icon128.png weapon_thumbnail_icon.png |
||||
Source |
||||
Weapon | ||||
Weapon.Build.cs WeaponAssetEditor.h .cpp 생성 WeaponAssetFactory.h .cpp WeaponCommand.h .cpp 생성 WeaponContextMenu.h .cpp WeaponModule.h .cpp WeaponStyle.h .cpp |
||||
Source | ||
Characters | ||
CAnimInstance.h .cpp CEnemy.h .cpp CPlayer.h .cpp ICharacter.h .cpp |
||
Components | ||
CMontagesComponent.h .cpp CMovementComponent.h .cpp CStateComponent.h .cpp CWeaponComponent.h .cpp |
||
Notifies | ||
CAnimNotifyState_BeginAction.h .cpp CAnimNotify_CameraShake.h .cpp CAnimNotifyState_EndAction.h .cpp CAnimNotify_EndState.h .cpp CAnimNotifyState_Collision.h .cpp CAnimNotifyState_Combo.h .cpp CAnimNotifyState_Equip.h .cpp |
||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Weapons | ||
CDoAction_Combo.h .cpp CAttachment.h .cpp CDoAction.h .cpp CEquipment.h .cpp CWeaponAsset.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp .Build.cs |
||
.uproject | ||
Weapon Plugin 만들기
Slate UI 의 디자인 패턴 - 재귀적 호출
new A() → Add(" ") → Add(" ")
- Slate UI의 디자인 패턴을 만들 때 자기 자료형으로 리턴하는 재귀적 호출을 사용한다.
Slate의 동적할당?
SNew(SButton) .Content() [ SNew(STextBlock) .Text( ) //여기위치 ]
SLATE_ARGUMENT
SLATE_EVENT
SLATE_ATTRIBUTE
- TAttibute<FText>
- 외부에서 값이 바뀌면 적용된다.
Weapon.Build.cs
Weapon.Build.cs
using UnrealBuildTool; public class Weapon : ModuleRules { public Weapon(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PrivateIncludePaths.Add(ModuleDirectory); PublicDependencyModuleNames.Add("Core"); PrivateDependencyModuleNames.Add("U2212_06");//프로젝트명 PrivateDependencyModuleNames.Add("CoreUObject"); PrivateDependencyModuleNames.Add("Engine"); PrivateDependencyModuleNames.Add("Slate"); PrivateDependencyModuleNames.Add("SlateCore"); PrivateDependencyModuleNames.Add("UnrealEd");//UFactory PrivateDependencyModuleNames.Add("EditorStyle");// } }
PrivateDependencyModuleNames.Add("EditorStyle"); 추가
WeaponCommand 생성
새 C++ 클래스 - 없음 - WeaponCommand 생성
WeaponCommand .h
#pragma once #include "CoreMinimal.h" #include "Framework/Commands/Commands.h" class WEAPON_API FWeaponCommand : public TCommands<FWeaponCommand> { public: FWeaponCommand(); ~FWeaponCommand(); void Startup(); public: void RegisterCommands() override; private: TSharedPtr<FExtender> Extender; TSharedPtr<FUICommandList> Command; TSharedPtr<FUICommandInfo> Id; private: void AddToolBar(FToolBarBuilder& InBuilder);//툴바에 버튼 추가 void OnClicked();//버튼이 눌렸을때 };
WeaponCommand .cpp
#include "WeaponCommand.h" #include "WeaponStyle.h" #include "WeaponAssetEditor.h" #include "LevelEditor.h" FWeaponCommand::FWeaponCommand() : TCommands("Toolbar_Buttons", FText::FromString(""), NAME_None, FEditorStyle::GetStyleSetName()) { Command = MakeShareable(new FUICommandList()); } FWeaponCommand::~FWeaponCommand() { if (Command.IsValid()) Command.Reset(); if (Extender.IsValid()) Extender.Reset(); } void FWeaponCommand::Startup() { FWeaponCommand::RegisterCommands(); Extender = MakeShareable(new FExtender()); FToolBarExtensionDelegate toolbar = FToolBarExtensionDelegate::CreateRaw(this, &FWeaponCommand::AddToolBar); Extender->AddToolBarExtension("Settings", EExtensionHook::After, Command, toolbar); FLevelEditorModule& levelEditor = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor"); levelEditor.GetToolBarExtensibilityManager()->AddExtender(Extender); } void FWeaponCommand::RegisterCommands() { #define LOCTEXT_NAMESPACE "" UI_COMMAND(Id, "Weapon", "", EUserInterfaceActionType::Button, FInputChord()); #undef LOCTEXT_NAMESPACE FExecuteAction action; action.BindRaw(this, &FWeaponCommand::OnClicked); Command->MapAction(Id, action, FCanExecuteAction()); } void FWeaponCommand::AddToolBar(FToolBarBuilder& InBuilder) { FString name = TEXT("웨폰"); InBuilder.AddSeparator(); InBuilder.AddToolBarButton(Id, NAME_None, FText::FromString(name), FText::FromString("Weapon Asset Editor"), FWeaponStyle::Get()->ToolBar_Icon, NAME_None); } void FWeaponCommand::OnClicked() { FWeaponAssetEditor::OpenWindow(); }
※ 툴바에 한글이 포함되는 경우




한글이 포함되는 파일을 다른 이름으로 저장 - 고급 저장 옵션: 유니코드(서명 있는 UTF-8) - 코드 페이지65001 적용
WeaponAssetEditor 생성
새 C++ 클래스 - 없음 - WeaponAssetEditor 생성
WeaponAssetEditor.h
#pragma once #include "CoreMinimal.h" #include "Toolkits/AssetEditorToolkit.h" class WEAPON_API FWeaponAssetEditor : public FAssetEditorToolkit { public: static void OpenWindow(FString InAssetName = ""); static void Shutdown(); private: static TSharedPtr<FWeaponAssetEditor> Instance; private: void Open(FString InAssetName); public: void RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager) override; private: TSharedRef<SDockTab> Spawn_ListViewTab(const FSpawnTabArgs& InArgs); public: FName GetToolkitFName() const override; FText GetBaseToolkitName() const override; FString GetWorldCentricTabPrefix() const override; FLinearColor GetWorldCentricTabColorScale() const override; private: static const FName EditorName; static const FName ListViewTabId; static const FName DetailTabId; private: FReply OnClicked(); };
부모로 설정한 : public FAssetEditorToolkit는 추상 클래스다.
- FAssetEditorToolkit에서 선언한 아래의 함수들을 WeaponAssetEditor에서 재정의한다.
- FName GetToolkitFName() const override;
- FText GetBaseToolkitName() const override;
- FString GetWorldCentricTabPrefix() const override;
- FLinearColor GetWorldCentricTabColorScale() const override;
- void RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager)
WeaponAssetEditor.cpp
#include "WeaponAssetEditor.h" #include "Weapons/CWeaponAsset.h" //설정한 이름들 const FName FWeaponAssetEditor::EditorName = "WeaponAssetEditor"; const FName FWeaponAssetEditor::ListViewTabId = "ListView"; const FName FWeaponAssetEditor::DetailTabId = "Details"; TSharedPtr<FWeaponAssetEditor> FWeaponAssetEditor::Instance = nullptr;//헤더에서 선언한 static 외부 초기화. void FWeaponAssetEditor::OpenWindow(FString InAssetName) { //아래의 코드 대신에 Shutdown()을 사용하면 안 된다! Shutdown()은 다른 곳에서도 콜이 되기 때문에 아래의 코드 대신에 사용하면 문제가 된다. if (Instance.IsValid()) //창이 만들어졌다면 { Instance->CloseWindow();//창을 닫는다. Instance.Reset(); Instance = nullptr; } Instance = MakeShareable(new FWeaponAssetEditor()); Instance->Open(InAssetName); } void FWeaponAssetEditor::Shutdown() { if (Instance.IsValid()) { Instance->CloseWindow(); Instance.Reset(); Instance = nullptr; } } void FWeaponAssetEditor::Open(FString InAssetName) { //Layout 설정 TSharedRef<FTabManager::FLayout> layout = FTabManager::NewLayout("WeaponAssetEditor_Layout") ->AddArea //전체화면의 메인 영역 ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.1f)//10%만 사용하겠다. ->AddTab(GetToolbarTabId(), ETabState::OpenedTab) ) ->Split ( FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.175f)//왼쪽 17.5% 사용 ->AddTab(ListViewTabId, ETabState::OpenedTab)//ListViewTabId ->SetHideTabWell(true) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.725f)//오른쪽 72.5% 사용 ->AddTab(DetailTabId, ETabState::OpenedTab)//DetailTabId ->SetHideTabWell(true) ) ) ); UCWeaponAsset* asset = NewObject<UCWeaponAsset>();//현재 없는 상태이므로 일단 빈 상태로 만들어준다. FAssetEditorToolkit::InitAssetEditor(EToolkitMode::Standalone, TSharedPtr<IToolkitHost>(), EditorName, layout, true, true, asset); } void FWeaponAssetEditor::RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager) { FAssetEditorToolkit::RegisterTabSpawners(InTabManager); FOnSpawnTab tab; tab.BindSP(this, &FWeaponAssetEditor::Spawn_ListViewTab); TabManager->RegisterTabSpawner(ListViewTabId, tab); } TSharedRef<SDockTab> FWeaponAssetEditor::Spawn_ListViewTab(const FSpawnTabArgs& InArgs) { TSharedPtr<SDockTab> tab = SNew(SDockTab) [ SNew(SButton) .OnClicked(this, &FWeaponAssetEditor::OnClicked)//OnClicked 함수 연결 [ SNew(STextBlock) .Text(FText::FromString("Test")) ] ]; return tab.ToSharedRef(); //return SNew(SDockTab); } FName FWeaponAssetEditor::GetToolkitFName() const { return EditorName;//외부에서 어떤 에디터 이름을 쓸 지 정해준다. } FText FWeaponAssetEditor::GetBaseToolkitName() const { return FText::FromName(EditorName);//외부에서 어떤 에디터 이름을 쓸 지 정해준다. } FString FWeaponAssetEditor::GetWorldCentricTabPrefix() const { return EditorName.ToString();////외부에서 어떤 식별자를 쓸 지 정해준다. } FLinearColor FWeaponAssetEditor::GetWorldCentricTabColorScale() const { return FLinearColor(0, 0, 1);//파란색으로 설정. } FReply FWeaponAssetEditor::OnClicked() { GLog->Log("Test"); return FReply::Handled();//Handled()는 처리하고 끝낸다. }
※ 참고
Editor에서는 Super:: 를 사용하면 안 된다.
※ 참고 - Handled(), Unhandled()
- Handled()를 사용하면 처리하고 끝낸다.
- Unhandled()를 사용하면 처리하지 않으면 끝낸다.
https://docs.unrealengine.com/4.26/en-US/BlueprintAPI/Widget/EventReply/Unhandled/
Unhandled
Unhandled
docs.unrealengine.com
WeaponModule
WeaponModule.h
#pragma once #include "CoreMinimal.h" #include "Modules/ModuleManager.h" class FWeaponModule : public IModuleInterface { public: virtual void StartupModule() override; virtual void ShutdownModule() override; private: TSharedPtr<class FWeaponContextMenu> ContextMenu;//언리얼 내 우클릭 대분류목록 TSharedPtr<class FWeaponCommand> Command;//언리얼 내 우클릭 대분류목록 };
언리얼 내 우클릭 대분류목록
- TSharedPtr<class FWeaponCommand> Command;
WeaponModule.cpp
#include "WeaponModule.h" #include "WeaponContextMenu.h" #include "WeaponStyle.h" #include "WeaponCommand.h" #include "IAssetTools.h" #include "AssetToolsModule.h" #define LOCTEXT_NAMESPACE "FWeaponModule" IMPLEMENT_MODULE(FWeaponModule, Weapon) void FWeaponModule::StartupModule() { IAssetTools& assetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get(); EAssetTypeCategories::Type categories = assetTools.RegisterAdvancedAssetCategory("WeaponAsset", FText::FromString("Weapon"));// ContextMenu = MakeShareable(new FWeaponContextMenu(categories)); assetTools.RegisterAssetTypeActions(ContextMenu.ToSharedRef()); Command = MakeShareable(new FWeaponCommand()); Command->Startup(); } void FWeaponModule::ShutdownModule() { if (ContextMenu.IsValid()) ContextMenu.Reset(); if (Command.IsValid()) Command.Reset(); FWeaponStyle::Shutdown(); } #undef LOCTEXT_NAMESPACE
실행화면

'⭐ Unreal Engine > UE Plugin - Slate UI' 카테고리의 다른 글
[UE] Weapon Plugin 6: 체크박스 만들기 (0) | 2023.06.08 |
---|---|
[UE] Weapon Plugin 5: 창 내부 Header, Child 구분하기 (0) | 2023.06.07 |
[UE] Weapon Plugin 4: 창 내에 데이터 넣어주기, 검색 기능 넣기 (0) | 2023.06.01 |
[UE] Weapon Plugin 3: 창 내부 영역 구분하기(SWeaponLeftArea, WeaponAssetEditor) (0) | 2023.05.31 |
[UE] Weapon Plugin 1: Slate UI Plugin 만들기 (0) | 2023.05.26 |
댓글
이 글 공유하기
다른 글
-
[UE] Weapon Plugin 5: 창 내부 Header, Child 구분하기
[UE] Weapon Plugin 5: 창 내부 Header, Child 구분하기
2023.06.07 -
[UE] Weapon Plugin 4: 창 내에 데이터 넣어주기, 검색 기능 넣기
[UE] Weapon Plugin 4: 창 내에 데이터 넣어주기, 검색 기능 넣기
2023.06.01 -
[UE] Weapon Plugin 3: 창 내부 영역 구분하기(SWeaponLeftArea, WeaponAssetEditor)
[UE] Weapon Plugin 3: 창 내부 영역 구분하기(SWeaponLeftArea, WeaponAssetEditor)
2023.05.31 -
[UE] Weapon Plugin 1: Slate UI Plugin 만들기
[UE] Weapon Plugin 1: Slate UI Plugin 만들기
2023.05.26
댓글을 사용할 수 없습니다.