【UE4】 第07讲 【MOBA制作日记】 实现自定义的行走控件
2017-02-28 09:39
1201 查看
在图形业,只有技术是不行的,你要明白我们从事的工作,我们可是在作诗,我们是诗人 - Nvidia创始人黄仁勋(图形皇帝)
(版权声明,禁止转载)
UE4制作产品时,实际上几乎所有的UI控件都需要自定义实现,UE4本身只提供少量基础的Button,Image,Text,参考这些自带控件的实现,根据需要进行自定义扩展还是比较灵活高效的,不会有太多的冗余。
参考UE4自带的SVirtualJoystick来实现一下行走控件SWalkWidget
实现过程分两步
第一步 实现UE4渲染部分的SWalkWidget,继承自SLeafWidget
SWalkWidget.h
SWalkWidget.cpp
获取控件需要的两个Image - Engine.Joystick.Image1 Engine.Joystick.Image2
在Construct 里指定大小和尺寸,用在OnPaint里指定绘制区域
通过ThumbPosition指定小圆圈的相对位置
第二步 实现C++反射后蓝图可编辑的UWalkWidget
这个类需要通过UE4向导创建,选择父类为Widget
WalkWidget.h
WalkWidget.cpp
编译成功之后,可以在Widget的蓝图编辑器里看到,可以直接拖入编辑区进行编辑
(版权声明,禁止转载)
UE4制作产品时,实际上几乎所有的UI控件都需要自定义实现,UE4本身只提供少量基础的Button,Image,Text,参考这些自带控件的实现,根据需要进行自定义扩展还是比较灵活高效的,不会有太多的冗余。
参考UE4自带的SVirtualJoystick来实现一下行走控件SWalkWidget
实现过程分两步
第一步 实现UE4渲染部分的SWalkWidget,继承自SLeafWidget
SWalkWidget.h
#pragma once #include "SWidget.h" #include "SLeafWidget.h" /** * */ class MOBAHERO_API SWalkWidget : public SLeafWidget { public: /** The settings and current state of each zone we render */ struct FControlInfo { FControlInfo() { // default to all 0 FMemory::Memzero(this, sizeof(*this)); CapturedPointerIndex = -1; InputScale = FVector2D(1.f, 1.f); } // Set by the game /** The brush to use to draw the background for joysticks, or unclicked for buttons */ TSharedPtr< FSlateDynamicImageBrush > Image1; /** The brush to use to draw the thumb for joysticks, or clicked for buttons */ TSharedPtr< FSlateDynamicImageBrush > Image2; /** The actual center of the control */ FVector2D Center; /** The size of a joystick that can be re-centered within InteractionSize area */ FVector2D VisualSize; /** The size of the thumb that can be re-centered within InteractionSize area */ FVector2D ThumbSize; /** The size of a the interactable area around Center */ FVector2D InteractionSize; /** The scale for control input */ FVector2D InputScale; /** The input to send from this control (for sticks, this is the horizontal/X input) */ FKey MainInputKey; /** The secondary input (for sticks, this is the vertical/Y input, unused for buttons) */ FKey AltInputKey; /** Positioned center in viewport */ FVector2D PositionedCenter; private: friend SWalkWidget; /** * Reset the control to a centered/inactive state */ void Reset(); // Current state /** The position of the thumb, in relation to the VisualCenter */ FVector2D ThumbPosition; /** For recentered joysticks, this is the re-center location */ FVector2D VisualCenter; /** The corrected actual center of the control */ FVector2D CorrectedCenter; /** The corrected size of a joystick that can be re-centered within InteractionSize area */ FVector2D CorrectedVisualSize; /** The corrected size of the thumb that can be re-centered within InteractionSize area */ FVector2D CorrectedThumbSize; /** The corrected size of a the interactable area around Center */ FVector2D CorrectedInteractionSize; /** The corrected scale for control input */ FVector2D CorrectedInputScale; /** Which pointer index is interacting with this control right now, or -1 if not interacting */ int32 CapturedPointerIndex; /** Time to activate joystick **/ float ElapsedTime; /** Visual center to be updated */ FVector2D NextCenter; /** Whether or not to send one last "release" event next tick */ bool bSendOneMoreEvent; /** Whether or not we need position the control against the geometry */ bool bHasBeenPositioned; /** Whether or not to update center position */ bool bNeedUpdatedCenter; }; SLATE_BEGIN_ARGS(SWalkWidget) {} SLATE_END_ARGS() void Construct(const FArguments& InArgs); virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; virtual FVector2D ComputeDesiredSize(float) const override; virtual FReply OnTouchStarted(const FGeometry& MyGeometry, const FPointerEvent& Event) override; virtual FReply OnTouchMoved(const FGeometry& MyGeometry, const FPointerEvent& Event) override; virtual FReply OnTouchEnded(const FGeometry& MyGeometry, const FPointerEvent& Event) override; virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; private: /** List of controls set by the UTouchInterface */ FControlInfo Control; /** True if the joystick should be visible */ uint32 bVisible : 1; /** Target opacity */ float CurrentOpacity; bool bPressed; };
SWalkWidget.cpp
获取控件需要的两个Image - Engine.Joystick.Image1 Engine.Joystick.Image2
在Construct 里指定大小和尺寸,用在OnPaint里指定绘制区域
通过ThumbPosition指定小圆圈的相对位置
#include "MobaHero.h" #include "SWalkWidget.h" #include "CoreStyle.h" void SWalkWidget::Construct(const FArguments& InArgs) { // CurrentOpacity = 0.4f; bVisible = 1; bPressed = false; UTexture2D* Tex(0); Control.Image1 = FCoreStyle::GetDynamicImageBrush("Engine.Joystick.Image1", Tex, "VirtualJoystick_Thumb"); Control.Image2 = FCoreStyle::GetDynamicImageBrush("Engine.Joystick.Image2", Tex, "VirtualJoystick_Background"); Control.Center = FVector2D(135.f,-135.f); Control.VisualSize = FVector2D(192.f,192.f); Control.CorrectedVisualSize = FVector2D(365.f,365.f); Control.VisualCenter = Control.CorrectedVisualSize / 2.f; Control.CorrectedThumbSize = FVector2D(150.f,150.f); Control.ThumbPosition = FVector2D(0.f,0.f); } //在这里绘制两个Image,大圆圈的先绘制,小圆圈的后绘制 int32 SWalkWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { int32 RetLayerId = LayerId; if (bVisible) { FLinearColor ColorAndOpacitySRGB = InWidgetStyle.GetColorAndOpacityTint(); ColorAndOpacitySRGB.A = CurrentOpacity; if (Control.Image2.IsValid()) { FSlateDrawElement::MakeBox( OutDrawElements, RetLayerId++, AllottedGeometry.ToPaintGeometry( Control.VisualCenter - FVector2D(Control.CorrectedVisualSize.X * 0.5f, Control.CorrectedVisualSize.Y * 0.5f), Control.CorrectedVisualSize), Control.Image2.Get(), MyClippingRect, ESlateDrawEffect::None, ColorAndOpacitySRGB ); } if (Control.Image1.IsValid()) { FSlateDrawElement::MakeBox( OutDrawElements, RetLayerId++, AllottedGeometry.ToPaintGeometry( Control.VisualCenter + Control.ThumbPosition - FVector2D(Control.CorrectedThumbSize.X * 0.5f, Control.CorrectedThumbSize.Y * 0.5f), Control.CorrectedThumbSize), Control.Image1.Get(), MyClippingRect, ESlateDrawEffect::None, ColorAndOpacitySRGB ); } } return RetLayerId; } FVector2D SWalkWidget::ComputeDesiredSize(float) const { return FVector2D(100, 100); } FReply SWalkWidget::OnTouchStarted(const FGeometry& MyGeometry, const FPointerEvent& Event) { FVector2D LocalCoord = MyGeometry.AbsoluteToLocal(Event.GetScreenSpacePosition()); Control.ThumbPosition = LocalCoord - Control.VisualCenter; bPressed = true; return FReply::Handled(); } FReply SWalkWidget::OnTouchMoved(const FGeometry& MyGeometry, const FPointerEvent& Event) { FVector2D LocalCoord = MyGeometry.AbsoluteToLocal(Event.GetScreenSpacePosition()); GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Walk Widget Touch Move")); if (bPressed) { Control.ThumbPosition = LocalCoord - Control.VisualCenter; } return FReply::Handled(); } FReply SWalkWidget::OnTouchEnded(const FGeometry& MyGeometry, const FPointerEvent& Event) { bPressed = false; return FReply::Handled(); } void SWalkWidget::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) { // }
第二步 实现C++反射后蓝图可编辑的UWalkWidget
这个类需要通过UE4向导创建,选择父类为Widget
WalkWidget.h
#pragma once #include "SWalkWidget.h" #include "Widget.h" #include "WalkWidget.generated.h" /** * */ UCLASS() class MOBAHERO_API UWalkWidget : public UWidget { GENERATED_BODY() protected: /** Native Slate Widget */ TSharedPtr<SWalkWidget> MyWalkWidget; //~ Begin UWidget Interface virtual TSharedRef<SWidget> RebuildWidget() override; //~ End UWidget Interface };
WalkWidget.cpp
#include "MobaHero.h" #include "WalkWidget.h" TSharedRef<SWidget> UWalkWidget::RebuildWidget() { MyWalkWidget = SNew(SWalkWidget); return MyWalkWidget.ToSharedRef(); }
编译成功之后,可以在Widget的蓝图编辑器里看到,可以直接拖入编辑区进行编辑
相关文章推荐
- 【UE4】 第08讲 【MOBA制作日记】 实现全方位的行走
- 【UE4】 第04讲 【MOBA制作日记】 隐藏新建工程自带的操作控件
- 【UE4】 第02讲 【MOBA制作日记】 安卓打包
- 【UE4】 第05讲 【MOBA制作日记】 发射物方向调整
- [Wap] 制作自定义WmlListAdapter来实现Mobile.List控件的各种效果
- 【UE4】 第03讲 【MOBA制作日记】 FSocket联网及角色位置同步
- [Wap] 制作自定义WmlListAdapter来实现Mobile.List控件的各种效果
- 【UE4】 第06讲 【MOBA制作日记】 碰撞事件响应
- [Wap] 制作自定义WmlListAdapter来实现Mobile.List控件的各种效果
- 制作自定义WmlListAdapter来实现Mobile.List控件的各种效果
- 【TomoEngine】 第八讲 【MOBA制作日记三】 角色行走
- 【UE4】 第11讲 【MOBA制作日记】 HTC Vive设备安装使用及手柄控制漫游
- 【UE4】 第12讲 【MOBA制作日记】 FSocket断线重连
- [Wap] 制作自定义WmlListAdapter来实现Mobile.List控件的各种效果
- 【UE4】 第10讲 【MOBA制作日记】 Matinee相机过场动画
- 【UE4】 第09讲 【MOBA制作日记】 隐藏默认创建的DefaultPawn
- 【UE4】 第01讲 【MOBA制作日记】 角色攻击事件及发射物
- 使用委托在用户自定义控件中实现事件响应
- 如何在DataGrid 控件中实现自定义分页操作
- VS2005下自定义用户控件 如何实现属性及方法的相关智能提示