UE4开发C++沙盒游戏教程笔记(二)(对应教程集数 6 ~ 8)
UE4开发C++沙盒游戏教程笔记(二)(对应教程 6 ~ 8)
- 前言
- 5. 语言切换功能实现
- 使用引擎自带的本地化工具
- 用代码切换语言显示
- 6. 自定义 Button 控件
- 7. Debug 与游戏设置控件
- 添加和使用 Debug 类
- 游戏设置控件
前言
笔者写的时候其实已经看到课程第一章完结了,只是因为感觉光看不写笔记属实没有什么收获才回过头来重新写。并且为了贴合课程每集的代码状态,代码是我一步步跟着老师的代码重新写在网页上的,并没有实机跑过,如果有热心的读者发现文中知识点或者代码上的纰漏,烦请指正。我会同步更新到文章,并且在顶部记录你的名字,作为你我一同为此笔记作出贡献的证明 : )
5. 语言切换功能实现
使用引擎自带的本地化工具
本节课会用到 UE4 自带的本地化功能。
新建一个 C++ 类,取名叫 SlAiInternation,路径为 /Public/Data/。用处是注册本地化文本。
这个类用不到 .cpp 文件,所以把 .cpp 给删掉(删除时不仅要在 Visual Studio 里移除文件,还要在文件夹内删除该文件)。
SlAiInternation.h
#pragma once#include "CoreMinimal.h"class SLAICOURSE_API SlAiInternation
{
public:// 作用是让下面定义的本地化文字不会报错static void Register(FText Value) {return;}
};// 定义一个本地化的域名
#define LOCTEXT_NAMESPACE "SlAiMenu"SlAiInternation::Register(LOCTEXT("Menu", "Menu")); // 定义本地化文本
// 下面是稍后会补充的其他本地化文本定义
SlAiInternation::Register(LOCTEXT("StartGame", "StartGame"));
SlAiInternation::Register(LOCTEXT("GameOption", "GameOption"));
SlAiInternation::Register(LOCTEXT("QuitGame", "QuitGame"))SlAiInternation::Register(LOCTEXT("NewGame", "NewGame"));
SlAiInternation::Register(LOCTEXT("LoadRecord", "LoadRecord"));SlAiInternation::Register(LOCTEXT("ChooseRecord", "ChooseRecord"));SlAiInternation::Register(LOCTEXT("RecordName", "RecordName"));
SlAiInternation::Register(LOCTEXT("EnterGame", "EnterGame"));
SlAiInternation::Register(LOCTEXT("EnterRecord", "EnterRecord"));
SlAiInternation::Register(LOCTEXT("RecordNameHint", "Input Record Name!"));
SlAiInternation::Register(LOCTEXT("NameRepeatedHint", "Record Name Repeated!"));SlAiInternation::Register(LOCTEXT("Chinese", "Chinese"));
SlAiInternation::Register(LOCTEXT("English", "English"));
SlAiInternation::Register(LOCTEXT("Music", "Music"));
SlAiInternation::Register(LOCTEXT("Sound", "Sound"));SlAiInternation::Register(LOCTEXT("GoBack", "GoBack"));#undef LOCTEXT_NAMESPACE // 本地化域名末尾// 另一种定义本地化文本的方式,其实就是 NSLOCTEXT() 需要额外指定域名
SlAiInternation::Register(NSLOCTEXT("SlAiMenu", "Menu", "Menu"))
然后在菜单栏 Widget 里替换原来的文本内容:
SSlAiMenuWidget.cpp
#include "UI/Widget/SSlAiMenuWidget.h"
#include "SlateOptMacros.h"
#include "SlAiStyle.h"
#include "SlAiMenuWidgetStyle.h"
#include "SBox.h"
#include "SImage.h"
#include "STextBlock.h"BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuWidget::Construct(const FArguments& InArgs)
{MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");ChildSlot[SAssignNew(RootSizeBox, SBox)[// ...省略前面的结构+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)// 如果标题依旧不能显示中文,建议在后续声明字体样式、配置数据后应用下面的代码// 第7集《自定义 Button 控件》会声明字体样式//.Font(MenuStyle->Font_40).Font(SlAiStyle::Get().GetFontStyle("MenuItemFont"))// 此处替换,这个方法的第一个参数就是刚刚的域名,第二个参数就是“键”,第三个就是“值”.Text(NSLOCTEXT("SlAiMenu", "Menu", "Menu"))]]]]];RootSizeBox->SetWidthOverride(600.f);RootSizeBox->SetHeightOverride(510.f);}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
随后在编辑器的 Window->Localization Dashboard 本地化仪表板(如果没有这个选项的话,大概是因为你的引擎版本是旧的,要在 Edit –> Edit Preferences –> Experimental –> Tools –>Localization 开启),将项目的 Source 源文件添加进本地化文本搜索范围。接下来是 添加需要本地化的语言类型 -> Gather Text -> 填入翻译后的文本 -> Count Words -> Compile Text。最后一步会生成一个独立格式的本地化文件,位置在 Content 目录下的一个本地化文件夹内。
随后运行游戏。在老师的游戏界面中,顶部菜单显示中文,而笔者这里依然显示英文,可能是笔者的引擎默认语言设置成了英文导致的。
用代码切换语言显示
最简单直接的方法,直接在菜单栏 Widget 的构造函数里调用即可。
SSlAiMenuWidget.cpp
#include "UI/Widget/SSlAiMenuWidget.h"
#include "SlateOptMacros.h"
#include "SlAiStyle.h"
#include "SlAiMenuWidgetStyle.h"
#include "SBox.h"
#include "SImage.h"
#include "STextBlock.h"#include "Internationalization.h" // 切换本地化语言用到的头文件BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuWidget::Construct(const FArguments& InArgs)
{MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");FInternationalization::Get().SetCurrentCulture(TEXT("en")); // 切换英文FInternationalization::Get().SetCurrentCulture(TEXT("zh")); // 切换中文ChildSlot[// ...省略结构]
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
笔者发现这种直接调用 “SetCurrentCulture(TEXT(“en”))” 方法会使你的引擎界面也一并变成英文。。?而且这个情况是不会反过来的,也就是说你调用 “SetCurrentCulture(TEXT(“zh”))” 不会让你的引擎界面变回中文,即便原来就是显示中文的语言设置,调用方法后引擎也会显示英文。此处原因不明,不过也可以看出这个方法就是直接改变引擎的本地化语言选项。
另一种更加妥当的切换语言显示的方法如下:(在尝试另一种方法前记得先去掉刚刚写的代码)
新建一个 C++ 类,取名叫 SlAiTypes,路径为 /Public/Data/。用处是存放数据结构。这个也不需要 .cpp 文件。
新建一个 C++ 类,取名叫 SlAiDataHandle,路径为 /Public/Data/。用处是数据控制。
SlAiTypes.h
#pragma once#include "CoreMinimal.h"// 定义语言种类的枚举
UENUM() // 枚举专用宏,用于反射
enum class ECultureTeam : uint8 {EN = 0,ZH
};
SlAiDataHandle.h
#pragma once#include "SlAiTypes.h" // 引入数据结构类的头文件
#include "CoreMinimal.h"// 这个类也使用单例模式
class SLAICOURSE_API SlAiDataHandle
{
public:SlAiDataHandle();static void Initialize();static TSharedPtr<SlAiDataHandle> Get();// 修改语言void ChangeLocalizationCulture(ECultureTeam Culture);public:// 保存当前语言种类ECultureTeam CurrentCulture;private:// 创建单例static TSharedRef<SlAiDataHandle> Create();private:static TSharedPtr<SlAiDataHandle> DataInstance;};
SlAiDataHandle.cpp
#include "Data/SlAiDataHandle.h"TSharedPtr<SlAiDataHandle> SlAiDataHandle::DataInstance = NULL;void SlAiDataHandle::Initialize()
{if (!DataInstance.IsValid()) {DataInstance = Create();}
}TSharedPtr<SlAiDataHandle> SlAiDataHandle::Get()
{Initialize();return DataInstance;
}TSharedRef<SlAiDataHandle> SlAiDataHandle::Create()
{TSharedRef<SlAiDataHandle> DataRef = MakeShareable(new SlAiDataHandle());return DataRef; // 下一节课程会补充
}SlAiDataHandle::SlAiDataHandle()
{
}void SlAiDataHandle::ChangeLocalizationCulture(ECultureTeam Culture)
{switch (Culture){case ECultureTeam::EN:FInternationalization::Get().SetCurrentCulture(TEXT("en"));break;case ECultureTeam::ZH:FInternationalization::Get().SetCurrentCulture(TEXT("zh"));break;}// 保存更改后的语言种类CurrentCulture = Culture;
}
目前写好了语言切换所要用到的两个类,后面会通过给界面创建勾选框来进行语言的切换。
6. 自定义 Button 控件
创建一个 SlateWidget 类 SlAiMenuItemWidget,路径为 UI/Widget/,作为菜单栏内的子条目
在 SlAiTypes.h 这个数据存储类里添加下面的内容,一会要用到
SlAiTypes.h
#pragma once#include "CoreMinimal.h"UENUM()
enum class ECultureTeam : uint8 {EN = 0,ZH
};// Menu 按钮的类型
// 额外知识点:没有添加供反射使用的宏,该类型就无法在蓝图里调用
namespace EMenuItem {enum Type{None,StartGame,GameOption,QuitGame,NewGame,LoadRecord,StartGameGoBack,GameOptionGoBack,NewGameGoBack,ChooseRecordGoBack,EnterGame,EnterRecord};
}
给子条目设置笔刷,添加3个字体类样式
SlAiMenuStyle.h
#pragma once#include "CoreMinimal.h"
#include "Styling/SlateWidgetStyle.h"
#include "Styling/SlateWidgetStyleContainerBase.h"
#include "SlateBrush.h"
#include "SlateFontInfo.h" // 字体头文件
#include "SlAiMenuWidgetStyle.generated.h"USTRUCT()
struct SLAICOURSE_API FSlAiMenuStyle : public FSlateWidgetStyle
{GENERATED_USTRUCT_BODY()// ... 省略中间的声明UPROPERTY(EditAnywhere, Category = "Menu")FSlateBrush TitleBorderBrush;// 子条目的笔刷UPROPERTY(EditAnywhere, Category = "MenuItem")FSlateBrush MenuItemBrush;// 60 号字体UPROPERTY(EditAnywhere, Category = "Common")FSlateFontInto Font_60;// 40 号字体UPROPERTY(EditAnywhere, Category = "Common")FSlateFontInto Font_40;// 30 号字体UPROPERTY(EditAnywhere, Category = "Common")FSlateFontInto Font_30;};// ... 略过此处类的声明
随后在菜单栏条目里添加两个宏,以及声明委托
SSlAiMenuItemWidget.h
#pragma once#include "CoreMinimal.h"
#include "SlAiTypes.h" // 引入数据存储类头文件
#include "Widgets/SCompoundWidget.h"// 定义点击事件委托,第一个参数是委托名,第二个参数是委托的参数,也印证了 OneParam 的意思
DECLARE_DELEGATE_OneParam(FItemClicked, const EMenuItem::Type)class SLAICOURSE_API SSlAiMenuItemWidget : public SCompoundWidget
{
public:SLATE_BEGIN_ARGS(SSlAiMenuItemWidget){}// 添加宏1SLATE_ATTRIBUTE(FText, ItemText)// 添加宏2SLATE_ATTRIBUTE(EMenuItem::Type, ItemType)// 添加按钮点击事件SLATE_EVENT(FItemClicked, OnClicked)SLATE_END_ARGS()void Construct(const FArguments& InArgs);// 重写组件的 OnMouseButtonDown 方法virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;// 重写按钮起来的方法virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;// 鼠标离开virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override;private:// 获取颜色FSlateColor GetTintColor() const;private:// 获取样式类const struct FSlAiMenuStyle *MenuStyle;// 按下事件委托,委托名作类型FItemClicked OnClicked;// 保存按钮子条目类型EMenuItem::Type ItemType;// 按钮是否已经按下bool IsMouseButtonDown;
};
SSlAiMenuItemWidget.cpp
#include "UI/Widget/SSlAiMenuItemWidget.h"
#include "SlateOptMacros.h"
// 补充下面5个头文件
#include "SlAiStyle.h"
#include "SlAiMenuWidgetStyle.h"
#include "SBox.h"
#include "SImage.h"
#include "STextBlock.h"BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
// 此处的形参 InArgs 可以获取到在头文件声明的属性宏
void SSlAiMenuItemWidget::Construct(const FArguments& InArgs)
{// 依旧是获取样式类MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");// 绑定委托OnClicked = InArgs._OnClicked;// 因为直接取会取到 TAttribute 类型的数据,所以要再调用一个 Get() 函数 ItemType = InArgs._ItemType.Get();ChildSlot[SNew(SBox).WidthOverride(500.f).HeightOverride(100.f)[SNew(SOverlay)+SOverlay::Slot().VAlign(VAlign_Fill).HAlign(HAlign_Fill)[SNew(SImage).Image(&MenuStyle->MenuItemBrush) // 运用刚刚补充的笔刷.ColorAndOpacity(this, &SSlAiMenuItemWidget::GetTintColor) // 颜色绑定]+SOverlay::Slot().VAlign(VAlign_Center).HAlign(HAlign_Center)[SNew(STextBlock).Text(InArgs._ItemText).Font(MenuStyle->Font_60) // 运用补充的字体样式]]];// 按钮按下状态初始化IsMouseButtonDown = false;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATIONFReply SSlAiMenuItemWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{IsMouseButtonDown = true;return FReply::Handled();
}FReply SSlAiMenuItemWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{// 如果按钮按下了并且 OnClicked 委托绑定有方法那就执行if(IsMouseButtonDown){IsMouseButtonDown = false;OnClicked.ExecuteIfBound(ItemType);}return FReply::Handled();
}void SSlAiMenuItemWidget::OnMouseLeave(const FPointerEvent& MouseEvent)
{IsMouseButtonDown = false;
}// 根据按钮状态设置按钮笔刷颜色
FSlateColor SSlAiMenuItemWidget::GetTintColor() const
{if(IsMouseButtonDown) return FLinearColor(1.f, 0.1f, 0.1f, 0.5f);return FLinearColor(1.f, 1.f, 1.f, 1.f);
}
随后在菜单栏 Widget 里添加这个新建的 Widget 到界面。
SSlAiMenuWidget.h
#pragma once#include "CoreMinimal.h"
#include "SlAiTypes.h"
#include "Widgets/SCompoundWidget.h"class SBox;
class STextBlock;
class SVerticalBox; // 添加垂直框的声明class SLAICOURSE_API SSlAiMenuWidget : public SCompoundWidget
{
public:SLATE_BEGIN_ARGS(SSlAiMenuWidget){}SLATE_END_ARGS()void Construct(const FArguments& InArgs);private:// 绑定到各个 MenuItem 的方法,MenuItem 即菜单栏子条目void MenuItemOnClicked(EMenuItem::Type ItemType);private:TSharedPtr<SBox> RootSizeBox;const struct FSlAiMenuStyle* MenuStyle;TSharedPtr<STextBlock> TitleText;// 该指针用来保存垂直列表TSharedPtr<SVerticalBox> ContentBox;
};
SSlAiMenuWidget.cpp
#include "UI/Widget/SSlAiMenuWidget.h"
#include "SlateOptMacros.h"
#include "SlAiStyle.h"
#include "SlAiMenuWidgetStyle.h"
#include "SBox.h"
#include "SImage.h"
#include "STextBlock.h"
#include "SSlAiMenuItemWidget.h" // 添加头文件
#include "SBoxPanel.h" // 添加容器的头文件以使用垂直框BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuWidget::Construct(const FArguments& InArgs)
{MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");ChildSlot[SAssignNew(RootSizeBox, SBox)[SNew(SOverlay)//... 先前的结构省略// 添加+SOverlay::Slot().HAlign(HAlign_Center).VAlign(VAlign_Top).Padding(FMargin(0.f, 130.f, 0.f, 0.f))[SAssignNew(ContentBox, SVerticalBox)// 在此处添加也可以,效果与下面一致,但是这样结构就被固定了/*+SVerticalBox::Slot()[SNew(SSlAiMenuItemWidget)]*/]]];RootSizeBox->SetWidthOverride(600.f);RootSizeBox->SetHeightOverride(510.f);// 在此处添加是为了可以动态添加和删除菜单栏里的内容ContentBox->AddSlot()[SNew(SSlAiMenuItemWidget)// 给子条目按钮的文本(宏1属性)赋值为 “开始游戏”.ItemText(NSLOCTEXT("SlAiMenu", "StartGame", "StartGame"))// 给子条目按钮的类型(宏2属性)赋值.ItemType(EMenuItem::StartGame)// 此处将 OnClicked 委托绑定到菜单栏这里的方法.OnClicked(this, &SSlAiMenuWidget::MenuItemOnClicked)];}
END_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SSlAiMenuWidget::MenuItemOnClicked(EMenuItem::Type ItemType)
{// 本集结尾用作测试的代码TitleText->SetText(NSLOCTEXT("SlAiMenu", "StartGame", "StartGame"));
}
本集的代码量相较前几集有点多。并且讲到了 Slate 的一些用法 和 委托。此处推荐几篇文章加深了解。
关于 Slate 的编程:
《(UE4 4.21 ) UE4 Slate 编程入门一之Slate控件基本的创建》写得很好,完全贴合本集内容
关于委托:
《【UE4笔记】各种Delegate委托的区别和应用》内容不多,适合初步接触
(动态多播委托的代码写得有错误,评论区也指出了)
《UE4技术总结——委托》内容较多,适合深入学习;底层实现部分比较复杂,根据读者水平决定是否进行阅读
(文章贴出来的一些代码有误,比如:“一个简单的声明单播委托的例子:”、“PayLoad 的举个例子” 那块,注意甄别)
最后跟着老师配置一下样式类蓝图的一些配置,如果点击开始游戏,标题文本变 “开始游戏” 则说明成功了。
7. Debug 与游戏设置控件
添加和使用 Debug 类
新建一个 C++ 类,取名为 SlAiHelper,路径是 /Public/Common/,作用是用来输出用于 Debug 的语句。同样,它也不需要用到 .cpp 文件
SlAiHelper.h
#pragma once#include "CoreMinimal.h"
#include "Engine/World.h"
#include "Engine/GameEngine.h"namespace SlAiHelper{FORCEINLINE void Debug(FString Message, float Duration = 3.f) {if (GEngine) {// 打印一段文字,输出文字,持续秒,颜色为黄色 GEngine->AddOnScreenDebugMessage(-1, Duration, FColor::Yellow, Message);}}
}
写完后在菜单栏 Widget 试验一下是否可用。
SSlAiMenuWidget.cpp
// ... 头文件引入省略
#include "SlAiHelper.h" // 引入头文件BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuWidget::Construct(const FArguments& InArgs)
{// ... 结构省略
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SSlAiMenuWidget::MenuItemOnClicked(EMenuItem::Type ItemType)
{SlAiHelper::Debug(FString("hhhh"), 5.f); // 用 Debug 语句取代原来的文本替换
}
运行后点 “开始游戏”,屏幕左上角显示黄色的 hhhh 则说明成功了。
游戏设置控件
创建一个 SlateWidget 类,取名为 SlAiGameOptionWidget。路径为 /Public/UI/Widget,作为游戏设置界面
先把刚刚添加的 Debug 语句注释掉,然后把新建的 Widget 添加到菜单栏 Widget 里。
SSlAiMenuWidget.cpp
// ... 省略头文件
// 添加三个头文件
#include "SSlAiGameOptionWidget.h"
#include "SlAiHelper.h"
#include "SlAiDataHandle.h"BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiMenuWidget::Construct(const FArguments& InArgs)
{MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");ChildSlot[// ...结构省略];RootSizeBox->SetWidthOverride(600.f);RootSizeBox->SetHeightOverride(510.f);ContentBox->AddSlot()[SNew(SSlAiGameOptionWidget) // 替换成刚刚新建的 Widget]; }
END_SLATE_FUNCTION_BUILD_OPTIMIZATIONvoid SSlAiMenuWidget::MenuItemOnClicked(EMenuItem::Type ItemType)
{// 注释掉//SlAiHelper::Debug(FString("hhhh"), 5.f);
}
给游戏设置 Widget 准备笔刷、文本颜色以及勾选框的两种状态的笔刷
SlAiMenuStyle.h
#pragma once// ... 省略头文件USTRUCT()
struct SLAICOURSE_API FSlAiMenuStyle : public FSlateWidgetStyle
{GENERATED_USTRUCT_BODY()// ... 省略中间的声明// 黑色颜色UPROPERTY(EditAnywhere, Category = "Common")FLinearColor FontColor_White;// 白色颜色UPROPERTY(EditAnywhere, Category = "Common")FLinearColor FontColor_Black;// 游戏设置的笔刷UPROPERTY(EditAnywhere, Category = "GameOption")FSlateBrush GameOptionBGBrush;// CheckBox 的选中状态笔刷UPROPERTY(EditAnywhere, Category = "GameOption")FSlateBrush CheckBoxBrush;// CheckBox 的非选中状态笔刷UPROPERTY(EditAnywhere, Category = "GameOption")FSlateBrush UnCheckBoxBrush;
};// ... 略过此处类的声明
给设置界面 Widget 的头文件添加用于存储样式类的变量,以及勾选框的指针、实现勾选框功能用到的方法
SSlAiGameOptionWidget.h
#pragma once#include "CoreMinimal.h"
#include "SlAiTypes.h" // 切换文本的方法要用到
#include "Widgets/SCompoundWidget.h"class SCheckBox;class SLAICOURSE_API SSlAiGameOptionWidget : public SCompoundWidget
{
public:SLATE_BEGIN_ARGS(SSlAiGameOptionWidget){}SLATE_END_ARGS()void Construct(const FArguments& InArgs);
private:// 统一设置样式void StyleInitialize();// 中文 CheckBox 事件void ZhCheckBoxStateChanged(ECheckBoxState NewState);// 英文 CheckBox 事件void EnCheckBoxStateChanged(ECheckBoxState NewState);private:// 获取样式类const struct FSlAiMenuStyle *MenuStyle;// 获取 CheckBox 指针TSharedPtr<SCheckBox> EnCheckBox;TSharedPtr<SCheckBox> ZhCheckBox;
};
SSlAiGameOptionWidget.cpp
#include "UI/Widget/SSlAiGameOptionWidget.h"
#include "SlateOptMacros.h"
// 添加一堆头文件
#include "SlAiStyle.h"
#include "SlAiMenuWidgetStyle.h"
#include "SBox.h"
#include "SImage.h"
#include "SBorder.h"
#include "SOverlay.h"
#include "STextBlock.h"
#inlcude "SBoxPanel.h"
#include "SCheckBox.h"#include "SlAiDataHandle.h"BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlAiGameOptionWidget::Construct(const FArguments& InArgs)
{// 获取样式类MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");ChildSlot[SNew(SBox).WidthOverride(500.f).HeightOverride(300.f)[SNew(SOverlay)+SOverlay::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Fill)[SNew(SImage).Image(&MenuStyle->GameOptionBGBrush)]+SOverlay::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Fill).Padding(FMargin(50.f))[SNew(SVerticalBox)// 设置界面的第一行+SVerticalBox::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Fill).FillHeight(1.f)[SNew(SHorizontalBox)+SHorizontalBox::Slot().HAlign(HAlign_Center).VAlign(VAlign_Center).FillWidth(1.f)[SAssignNew(ZhCheckBox, SCheckBox)// 绑定方法,一旦勾选框状态变更则调用这个方法.OnCheckStateChanged(this, &SSlAiGameOptionWidget::ZhCheckBoxStateChanged)[SNew(STextBlock).Font(MenuStyle->Font_40).ColorAndOpacity(MenuStyle->FontColor_Black).Text(NSLOCTEXT("SlAiMenu", "Chinese", "Chinese"))]]+SHorizontalBox::Slot().HAlign(HAlign_Center).VAlign(VAlign_Center).FillWidth(1.f)[SAssignNew(EnCheckBox, SCheckBox).OnCheckStateChanged(this, &SSlAiGameOptionWidget::EnCheckBoxStateChanged)[SNew(STextBlock).Font(MenuStyle->Font_40).ColorAndOpacity(MenuStyle->FontColor_Black).Text(NSLOCTEXT("SlAiMenu", "English", "English"))]]]// 第二行+SVerticalBox::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Fill).FillHeight(1.f)[SNew(SOverlay)]// 第三行+SVerticalBox::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Fill).FillHeight(1.f)[SNew(SOverlay)]]]];// 执行初始化操作,即给勾选框设置笔刷和当前状态StyleInitialize();
}void SSlAiGameOptionWidget::StyleInitialize()
{// 设置 ZhCheckBox 样式ZhCheckBox->SetUncheckedImage(&MenuStyle->UnCheckedBoxBrush);ZhCheckBox->SetUncheckedHoveredImage(&MenuStyle->UnCheckedBoxBrush);ZhCheckBox->SetUncheckedPressedImage(&MenuStyle->UnCheckedBoxBrush);ZhCheckBox->SetCheckedImage(&MenuStyle->CheckedBoxBrush);ZhCheckBox->SetCheckedHoveredImage(&MenuStyle->CheckedBoxBrush);ZhCheckBox->SetCheckedPressedImage(&MenuStyle->CheckedBoxBrush);// 设置 EnCheckBox 样式EnCheckBox->SetUncheckedImage(&MenuStyle->UnCheckedBoxBrush);EnCheckBox->SetUncheckedHoveredImage(&MenuStyle->UnCheckedBoxBrush);EnCheckBox->SetUncheckedPressedImage(&MenuStyle->UnCheckedBoxBrush);EnCheckBox->SetCheckedImage(&MenuStyle->CheckedBoxBrush);EnCheckBox->SetCheckedHoveredImage(&MenuStyle->CheckedBoxBrush);EnCheckBox->SetCheckedPressedImage(&MenuStyle->CheckedBoxBrush);// 根据当前语言设置勾选框状态switch (SlAiDataHandle::Get()->CurrentCulture){case ECultureTeam::EN:EnCheckBox->SetIsChecked(ECheckBoxState::Checked);ZhCheckBox->SetIsChecked(ECheckBoxState::Unchecked);break;case ECultureTeam::ZH:EnCheckBox->SetIsChecked(ECheckBoxState::Unchecked);ZhCheckBox->SetIsChecked(ECheckBoxState::Checked);break;}
}END_SLATE_FUNCTION_BUILD_OPTIMIZATION// 中文 CheckBox 事件
void SSlAiGameOptionWidget::ZhCheckBoxStateChanged(ECheckBoxState NewState)
{// 设置两个框的状态EnCheckBox->SetIsChecked(ECheckBoxState::Unchecked);ZhCheckBox->SetIsChecked(ECheckBoxState::Checked);// 告诉数据控制类转换为中文SlAiDataHandle::Get()->ChangeLocalizationCulture(ECultureTeam::ZH);
}
// 英文 CheckBox 事件
void SSlAiGameOptionWidget::EnCheckBoxStateChanged(ECheckBoxState NewState)
{// 设置两个框的状态EnCheckBox->SetIsChecked(ECheckBoxState::Checked);ZhCheckBox->SetIsChecked(ECheckBoxState::Unchecked);// 告诉数据控制类转换为英文SlAiDataHandle::Get()->ChangeLocalizationCulture(ECultureTeam::EN);
}
最后初始化语言为中文,用于设置勾选框的状态
SlAiDataHandle.cpp
#include "Data/SlAiDataHandle.h"
#include "Internationalization/Internationalization.h" // 本集结尾会加上// ...省略SlAiDataHandle::SlAiDataHandle()
{// 初始化为中文CurrentCulture = ECultureTeam::ZH;
}// ... 省略
跟着老师配置样式类,运行后勾选框切换状态和笔刷正常、中英文切换正常,说明成功了。
本集内容不难,如果勾选框那一段没看明白的话建议自己在 UMG 里用一下勾选框,或者看看勾选框的用法视频。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
