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