[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/
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