Fork me on GitHub

UE4 从无到有纯 C++ & Slate 开发沙盒游戏(五) 菜单布局实现

修改主菜单布局,增加菜单标题与左右侧小组件

首先创建菜单栏的中央UI

添加菜单指针到头文件

SSlAiMenuHUDWidget.h

#include "CoreMinimal.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/SOverlay.h"    

class SLAICOURSE_API SSlAiMenuHUDWidget : public SCompoundWidget
{
public:
    SLATE_BEGIN_ARGS(SSlAiMenuHUDWidget)
    {}
    SLATE_END_ARGS()

    /** Constructs this widget with InArgs */
    void Construct(const FArguments& InArgs);

private:
    //绑定UIScaler的函数
    float GetUIScaler() const;
    
    //获取屏幕尺寸
    FVector2D GetViewportSize() const;

private:
    const struct FSlAiMenuStyle* MenuStyle;

    TAttribute<float> UIScaler;
//SOverlay::FOverlaySlot* ImageSlot;

    //菜单指针
    TSharedPtr<class SSlAiMenuWidget> MenuWidget;
};

 

实例化MenuWidget

SSlAiMenuHUDWidget.cpp

#include "UI/Widget/SSlAiMenuHUDWidget.h"
#include "SlateOptMacros.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Images/SImage.h"
#include "UI/Style/SlAiStyle.h"
#include "UI/Style/SlAiMenuWidgetStyle.h"
#include "Widgets/Layout/SDPIScaler.h"
#include "UI/Widget/SSlAiMenuWidget.h"

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuHUDWidget::Construct(const FArguments& InArgs)
{
    /*
    获取编辑器的MenuStule的名字    */
    MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");

    /*
    绑定缩放规则方法,如果窗口有改变时将会调用GetUIScaler方法    */
    UIScaler.Bind(this, &SSlAiMenuHUDWidget::GetUIScaler);

    /*
    ChildSlot 是层级一样的东西,UI所有的东西都会放到这个下    */
    ChildSlot
    [
        SNew(SDPIScaler)
        .DPIScale(UIScaler)
        [
            SNew(SOverlay)
            
            //主菜单背景图
            +SOverlay::Slot()                                                //Slot 添加插槽
                .HAlign(HAlign_Fill)                                         //_Fill 填充
                .VAlign(VAlign_Fill)
                [
                    SNew(SImage).Image(&MenuStyle->MenuHUDBackgroundBrush)
                ]

            //主菜单栏中央UI
            + SOverlay::Slot()
                .HAlign(HAlign_Center)                                 //_Center 居中
                .VAlign(VAlign_Center)
                [
                    SAssignNew(MenuWidget, SSlAiMenuWidget)            //将MenuWidget实例化并放置到画面中央
                ]
        ]
    ];
}

END_SLATE_FUNCTION_BUILD_OPTIMIZATION


/*
绑定UIScaler的函数,通过获取的ViewportSize的高度来设置Scaler*/
float SSlAiMenuHUDWidget::GetUIScaler() const
{
    /*
    获取高度除以1080来获得组件的缩放比例*/
    return GetViewportSize().Y / 2160;
}

/*
获取屏幕尺寸*/
FVector2D SSlAiMenuHUDWidget::GetViewportSize() const
{
    /*
    设定屏幕分辨率*/
    FVector2D Result(3840, 2160);

    if (GEngine && GEngine->GameViewport)
    {
        GEngine->GameViewport->GetViewportSize(Result);
    }

    return Result;
}

 

 

 

之前在 SlAiStyle.cpp 中声明了字体

#include "UI/Style/SlAiStyle.h"
#include "Runtime/Engine/Public/Slate/SlateGameResources.h"

TSharedPtr<FSlateStyleSet> SlAiStyle::SlAiStyleInstance = NULL;

void SlAiStyle::Initialze()
{
    //注册 SlAiStyleInstance 具体为啥需要看下源码
    if (!SlAiStyleInstance.IsValid())
    {
        SlAiStyleInstance = Create();
        FSlateStyleRegistry::RegisterSlateStyle(*SlAiStyleInstance);
    }
}

FName SlAiStyle::GetStyleSetName()
{
    static FName StyleSetName(TEXT("SlAiStyle"));
    return StyleSetName;
}

void SlAiStyle::ShutDown()
{
    //取消注册
    FSlateStyleRegistry::UnRegisterSlateStyle(*SlAiStyleInstance);

    //确保是唯一的
    ensure(SlAiStyleInstance.IsUnique());
    
    //重置
    SlAiStyleInstance.Reset();
}

const ISlateStyle& SlAiStyle::Get()
{
    return *SlAiStyleInstance;
}

TSharedRef<class FSlateStyleSet> SlAiStyle::Create()
{
    //蓝图所存放的路径
    TSharedRef<FSlateStyleSet> StyleRef = FSlateGameResources::New(SlAiStyle::GetStyleSetName(), "/Game/UI/Style", "/Game/UI/Style");

    //这里也可以定义样式,比如定义一个字体样式,样式是MenuItemFont,类型是FSlateFontInfo ,参数为它的.ttf文件,和字体大小
    StyleRef->Set("MenuItemFont", FSlateFontInfo("Roboto-Regular.ttf", 50));

    return StyleRef;
}

 

 

声明相关UI的样式

SlAiMenuWidgetStyle.h

#include "CoreMinimal.h"
#include "Styling/SlateWidgetStyle.h"
#include "Styling/SlateWidgetStyleContainerBase.h"
#include "Styling/SlateBrush.h"
#include "SlAiMenuWidgetStyle.generated.h"

USTRUCT()
struct SLAICOURSE_API FSlAiMenuStyle : public FSlateWidgetStyle
{
    GENERATED_USTRUCT_BODY()

    FSlAiMenuStyle();
    virtual ~FSlAiMenuStyle();

    // FSlateWidgetStyle
    virtual void GetResources(TArray<const FSlateBrush*>& OutBrushes) const override;
    static const FName TypeName;
    virtual const FName GetTypeName() const override { return TypeName; };
    static const FSlAiMenuStyle& GetDefault();

    /*定义笔刷
    *     主背景图片*/
    UPROPERTY(EditAnywhere, Category = MenuHUD)
        FSlateBrush MenuHUDBackgroundBrush;

    /*定义笔刷
    *     主背景图片*/
    UPROPERTY(EditAnywhere, Category = Menu)
        FSlateBrush MenuBackgroundBrush;

    /*定义笔刷
    *     Menu左图标的Brush*/
    UPROPERTY(EditAnywhere, Category = Menu)
        FSlateBrush LeftIconBrush;

    /*定义笔刷
    *     Menu右图标的Brush*/
    UPROPERTY(EditAnywhere, Category = Menu)
        FSlateBrush RightIconBrush;

    /*定义笔刷
*     Menu标题Border的Brush*/
    UPROPERTY(EditAnywhere, Category = Menu)
        FSlateBrush TitleBorderBrush;
};

/**
 */
UCLASS(hidecategories=Object, MinimalAPI)
class USlAiMenuWidgetStyle : public USlateWidgetStyleContainerBase
{
    GENERATED_BODY()

public:
    /** The actual data describing the widget appearance. */
    UPROPERTY(Category=Appearance, EditAnywhere, meta=(ShowOnlyInnerProperties))
    FSlAiMenuStyle WidgetStyle;

    virtual const struct FSlateWidgetStyle* const GetStyle() const override
    {
        return static_cast< const struct FSlateWidgetStyle* >( &WidgetStyle );
    }
};

 

相关实现

SSlAiMenuWidget.cpp

#include "UI/Widget/SSlAiMenuWidget.h"
#include "SlateOptMacros.h"
#include "UI/Style/SlAiStyle.h"
#include "UI/Style/SlAiMenuWidgetStyle.h"
#include "Widgets/Layout/SBox.h"                    //一版会把SlateWidget的根组件设成SBox
#include "Widgets/Images/SImage.h"
#include "Widgets/Text/STextBlock.h"

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuWidget::Construct(const FArguments& InArgs)
{
    //获取MenuStyle
    MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");
    
    ChildSlot
    [
        /*
        没有Slot,没有Slot要么不能插入子组件,要么只能插入一个子组件,SizeBox 只能插入一个子组件*/
        SAssignNew(RootSizeBox, SBox)
        [
            SNew(SOverlay)

            +SOverlay::Slot()
                .HAlign(HAlign_Fill)
                .VAlign(VAlign_Fill)
                .Padding(FMargin(0.f, 50.f, 0.f, 0.f))        //FMargin 间隔(左 上 右 下)
                [
                    SNew(SImage)
                    .Image(&MenuStyle->MenuBackgroundBrush)
                ]

            +SOverlay::Slot()
                .HAlign(HAlign_Left)
                .VAlign(VAlign_Center)
                .Padding(FMargin(0.f, 25.f, 0.f, 0.f))
                [
                    SNew(SImage).Image(&MenuStyle->LeftIconBrush)
                ]

            + SOverlay::Slot()
                .HAlign(HAlign_Right)
                .VAlign(VAlign_Center)
                .Padding(FMargin(0.f, 25.f, 0.f, 0.f))
                [
                    SNew(SImage).Image(&MenuStyle->RightIconBrush)
                ]

            + SOverlay::Slot()
                .HAlign(HAlign_Center)
                .VAlign(VAlign_Top)
                [
                    SNew(SBox)
                    .WidthOverride(400.f)
                    .HeightOverride(100.f)
                    [
                        SNew(SBorder)
                        .BorderImage(&MenuStyle->TitleBorderBrush)
                        .HAlign(HAlign_Center)
                        .VAlign(VAlign_Center)
                        [
                            SAssignNew(TitleText, STextBlock)
                            .Font(SlAiStyle::Get().GetFontStyle("MenuItemFort"))
                            .Text(FText::FromString("I am 哈哈"))

                        ]
                    ]
                ]
        ]
    ];

    /*
    RootSizeBox在生成的时候没有设置他的宽和高,这里设置下*/
    RootSizeBox->SetWidthOverride(600.f);
    RootSizeBox->SetHeightOverride(510.f);

}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

 

posted @ 2021-07-23 11:52  索智源  阅读(528)  评论(0编辑  收藏  举报