(UE4 4.21 ) UE4扩展编辑器模式(FEdMode)

前言

在UE4中存在内置的五种编辑器模式,如Place模式,Paint,  Landscape, Foliage, GeometryEdit模式,在每一种模式下,我们的编辑器视口有不同的各种操作,比如Place模式下就是摆放和编辑各种Actor,而Landscape模式下就是创建地形以及编辑地形,在Landscape模式下无法选中Actor。总之各种模式下,视口操作Actor的行为是不一样的,这就是“模式(Mode)”.

 

FEdMode

我们可以通过FEdMode定制我们的模式。

创建模式(FEdMode)

(1)在模块注册(注销)模式

void FMyTestModeModule::StartupModule()
{
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
	FEditorModeRegistry::Get().RegisterMode<FMyTestModeEdMode>(FMyTestModeEdMode::EM_MyTestModeEdModeId, LOCTEXT("MyTestModeEdModeName", "MyTestModeEdMode"), FSlateIcon(), true);
}


void FMyTestModeModule::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.
	FEditorModeRegistry::Get().UnregisterMode(FMyTestModeEdMode::EM_MyTestModeEdModeId);
}

(2)继承FEdMode,定制我们的模式:

class FMyTestModeEdMode : public FEdMode
{
public:
	const static FEditorModeID EM_MyTestModeEdModeId;
public:
	FMyTestModeEdMode();
	virtual ~FMyTestModeEdMode();

	// FEdMode interface
	virtual void Enter() override;
	virtual void Exit() override;
	bool UsesToolkits() const override;
	// End of FEdMode interface
};
const FEditorModeID FMyTestModeEdMode::EM_MyTestModeEdModeId = TEXT("EM_MyTestModeEdMode");

void FMyTestModeEdMode::Enter()
{
	FEdMode::Enter();

	if (!Toolkit.IsValid() && UsesToolkits())
	{
		Toolkit = MakeShareable(new FMyTestModeEdModeToolkit);
		Toolkit->Init(Owner->GetToolkitHost());
	}
}

void FMyTestModeEdMode::Exit()
{
	if (Toolkit.IsValid())
	{
		FToolkitManager::Get().CloseToolkit(Toolkit.ToSharedRef());
		Toolkit.Reset();
	}

	// Call base Exit method to ensure proper cleanup
	FEdMode::Exit();
}

bool FMyTestModeEdMode::UsesToolkits() const
{
	return true;
}

(3)在FModeToolkit中扩展我们的模式内容

class SCompoundWidget;

class FMyTestModeEdModeToolkit : public FModeToolkit
{
public:

	FMyTestModeEdModeToolkit();
	
	/** FModeToolkit interface */
	virtual void Init(const TSharedPtr<IToolkitHost>& InitToolkitHost) override;

	/** IToolkit interface */
	virtual class FEdMode* GetEditorMode() const override;
	virtual TSharedPtr<class SWidget> GetInlineContent() const override;

private:
	TSharedPtr<SCompoundWidget> ToolkitWidget;
};

void FMyTestModeEdModeToolkit::Init(const TSharedPtr<IToolkitHost>& InitToolkitHost)
{
	ToolkitWidget = SNew(SMyCompoundWidget);

	FModeToolkit::Init(InitToolkitHost);
}

class FEdMode* FMyTestModeEdModeToolkit::GetEditorMode() const
{
	return GLevelEditorModeTools().GetActiveMode(FMyTestModeEdMode::EM_MyTestModeEdModeId);
}

TSharedPtr<SWidget> FMyTestModeEdModeToolkit::GetInlineContent() const
{
	return ToolkitWidget;
}

其中GetInlineContent返回的就是我们在模式面板定制的SWidget内容,

模式(FEdMode)界面创建的流程

 

模式(FEdMode)相关常用的函数

FEdMode的视口重载函数

基本函数

Enter(进入模式),Exit(退出模式),Tick(在模式中Tick)

	// FEdMode interface
	//进入模式函数
	virtual void Enter() override;

	//退出模式函数
	virtual void Exit() override;

	//Tick函数
	virtual void Tick(FEditorViewportClient* ViewportClient, float DeltaTime) override;

和视口显示相关

(1)控制视口鼠标样式,,返回False代表用默认的,返回True则使用OutCursor指定的


virtual bool GetCursor(EMouseCursor::Type& OutCursor) const;

(2)控制选中一个Actor的TransformWidget是否显示, 返回True,则可以显示,反之不显示。TransformWidget消失后不能在移动Actor


virtual bool UsesTransformWidget() const;

(3)在编辑器Viewport绘制基本图元,图形等

FCanvas* Canvas的DrawItem可以绘制继承FCanvasItem的各种图元()

virtual void DrawHUD(FEditorViewportClient* ViewportClient, FViewport* Viewport, const FSceneView* View, FCanvas* Canvas);

void FMyTestModeEdMode::DrawHUD(FEditorViewportClient* ViewportClient, FViewport* Viewport, const FSceneView* View, FCanvas* Canvas)
{
	FCanvasLineItem CanvasLineItem(FVector2D(0, 0), FVector2D(100.0f, 100.0f));
	Canvas->DrawItem(CanvasLineItem);
}


可绘制的基本图元
//FCanvasTriangleItem
//FCanvasTextItem
//FCanvasBorderItem
//FCanvasTileItem
//FCanvasLineItem

 

和视口输入控制相关

(1) 在编辑器视口鼠键的输入

返回True,则鼠标右键按下无法在控制视口旋转,反之返回False可以。
 

virtual bool InputKey(FEditorViewportClient* ViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event);

按键(包括了鼠标和键盘,限于篇幅,只截取部分),在InputCoreType.h文件

struct INPUTCORE_API EKeys
{
	static const FKey AnyKey;

	static const FKey MouseX;
	static const FKey MouseY;
	static const FKey MouseScrollUp;
	static const FKey MouseScrollDown;
	static const FKey MouseWheelAxis;

	static const FKey LeftMouseButton;
	static const FKey RightMouseButton;
	static const FKey MiddleMouseButton;
	static const FKey ThumbMouseButton;
	static const FKey ThumbMouseButton2;

	static const FKey BackSpace;
	static const FKey Tab;
	static const FKey Enter;
	static const FKey Pause;

	static const FKey CapsLock;
	static const FKey Escape;
	static const FKey SpaceBar;
	static const FKey PageUp;
	static const FKey PageDown;
	static const FKey End;
	static const FKey Home;

	static const FKey Left;
	static const FKey Up;
	static const FKey Right;
	static const FKey Down;

	static const FKey Insert;
	static const FKey Delete;

	static const FKey Zero;
	static const FKey One;
	static const FKey Two;

按键事件

enum EInputEvent
{
	IE_Pressed              =0,
	IE_Released             =1,
	IE_Repeat               =2,
	IE_DoubleClick          =3,
	IE_Axis                 =4,
	IE_MAX                  =5,
};

至于出现了 “鼠键同时和Ctrl,Shift,Alt同时按下”,也就是“Ctr+”, "Shift+","Alt+", 得通过FViewport* Viewport来判断,在UnrealClient.cpp提供了判断Ctrl,Shift,Alt三个键是否按下的判断函数

ENGINE_API bool IsCtrlDown(FViewport* Viewport) { return (Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl)); }
ENGINE_API bool IsShiftDown(FViewport* Viewport) { return (Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift)); }
ENGINE_API bool IsAltDown(FViewport* Viewport) { return (Viewport->KeyState(EKeys::LeftAlt) || Viewport->KeyState(EKeys::RightAlt)); }

(2)按下鼠标键的瞬间

virtual bool MouseEnter(FEditorViewportClient* ViewportClient, FViewport* Viewport, int32 x, int32 y);

(3)释放鼠标键的瞬间

virtual bool MouseLeave(FEditorViewportClient* ViewportClient, FViewport* Viewport);

(4)释放状态的鼠标键在视口中移动

//按下鼠标键在视口移动
	virtual bool CapturedMouseMove(FEditorViewportClient* InViewportClient, FViewport* InViewport, int32 InMouseX, int32 InMouseY);

(5)按下鼠标键在视口移动

virtual bool CapturedMouseMove(FEditorViewportClient* InViewportClient, FViewport* InViewport, int32 InMouseX, int32 InMouseY);

和UObject的GC相关

在定制我们的FEdMode,经常包含了各种UObject,FEdMode继承了FGCObject,因此在FEdMode创建的各种UObject对象在

AddReferencedObjects函数中添加到“引用对象集合”,具体可参考博客(UE4 4.20 )UE4的GC(垃圾回收)编程规范

class UNREALED_API FEdMode : public TSharedFromThis<FEdMode>, public FGCObject, public FEditorCommonDrawHelper
virtual void AddReferencedObjects(FReferenceCollector& Collector) override {}

和FEdMode相关非内置的应用技巧

(1)利用模式声明的ID获取模式, 方便获取模式中的各种变量


FMyTestModeEdMode* aaa = (FMyTestModeEdMode*)GLevelEditorModeTools().GetActiveMode(FMyTestModeEdMode::EM_MyTestModeEdModeId);

(2)获取视口鼠标点击的mesh或Actor,也就是鼠标在视口的光线求交

将鼠标在视口的位置转为世界空间的位置

/** Trace under the mouse cursor and return the landscape hit and the hit location (in landscape quad space) */
bool FEdModeLandscape::LandscapeMouseTrace(FEditorViewportClient* ViewportClient, float& OutHitX, float& OutHitY)
{
	int32 MouseX = ViewportClient->Viewport->GetMouseX();
	int32 MouseY = ViewportClient->Viewport->GetMouseY();

	return LandscapeMouseTrace(ViewportClient, MouseX, MouseY, OutHitX, OutHitY);
}


bool FEdModeLandscape::LandscapeMouseTrace(FEditorViewportClient* ViewportClient, int32 MouseX, int32 MouseY, FVector& OutHitLocation)
{
	// Cache a copy of the world pointer	
	UWorld* World = ViewportClient->GetWorld();

	// Compute a world space ray from the screen space mouse coordinates
	FSceneViewFamilyContext ViewFamily(FSceneViewFamilyContext::ConstructionValues(ViewportClient->Viewport, ViewportClient->GetScene(), ViewportClient->EngineShowFlags)
		.SetRealtimeUpdate(ViewportClient->IsRealtime()));

	FSceneView* View = ViewportClient->CalcSceneView(&ViewFamily);
	FViewportCursorLocation MouseViewportRay(View, ViewportClient, MouseX, MouseY);
	FVector MouseViewportRayDirection = MouseViewportRay.GetDirection();

	FVector Start = MouseViewportRay.GetOrigin();
	FVector End = Start + WORLD_MAX * MouseViewportRayDirection;
	if (ViewportClient->IsOrtho())
	{
		Start -= WORLD_MAX * MouseViewportRayDirection;
	}

}

 

参考资料

【1】UE4地形编辑器源码:Engine\Source\Editor\LandscapeEditor

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值