【UE4】 第07讲 【MOBA制作日记】 实现自定义的行走控件

来源:互联网 发布:程序员教程(第4版) 编辑:程序博客网 时间:2024/05/16 06:19

      在图形业,只有技术是不行的,你要明白我们从事的工作,我们可是在作诗,我们是诗人 - Nvidia创始人黄仁勋(图形皇帝)

 

    (版权声明,禁止转载)

     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 0FMemory::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 Interfacevirtual 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的蓝图编辑器里看到,可以直接拖入编辑区进行编辑

              

0 0
原创粉丝点击