Fork me on GitHub

UE4 从无到有纯 C++ & Slate 开发沙盒游戏(十三) 进入游戏控件

下图为菜单结构,到目前为止已经实现了游戏设置控件(绿色的部分),还缺少开始游戏控件,这个部将会开始实现 "输入存档名""选择存档" 的部分

 

 

 

首先我们在 UI/Widget 文件夹下新建两个 SlateWidget 组件

SlAiNewGameWidget 与 SlAiChooseRecordWidget

 

 

d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\UI\Widget\SSlAiNewGameWidget.h

 1 #include "CoreMinimal.h"
 2 #include "Widgets/SCompoundWidget.h"
 3 
 4 class SEditableTextBox;
 5 
 6 /**
 7  * 
 8  */
 9 class SLAICOURSE_API SSlAiNewGameWidget : public SCompoundWidget
10 {
11 public:
12     SLATE_BEGIN_ARGS(SSlAiNewGameWidget)
13     {}
14     SLATE_END_ARGS()
15 
16     /** Constructs this widget with InArgs */
17     void Construct(const FArguments& InArgs);
18 
19     //是否可以进入游戏
20     bool AllowEnterGame();
21 
22 private:
23     //获取MenuStyle
24     const struct FSlAiMenuStyle* MenuStyle;
25 
26     //输入框指针
27     TSharedPtr<SEditableTextBox> EditTextBox;
28 };

 

 D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\UI\Widget\SSlAiNewGameWidget.cpp

 1 #include "UI/Widget/SSlAiNewGameWidget.h"
 2 #include "SlateOptMacros.h"
 3 #include "UI/Style/SlAiStyle.h"
 4 #include "UI/Style/SlAiMenuWidgetStyle.h"
 5 #include "Widgets/Layout/SBox.h"                                        //一版会把SlateWidget的根组件设成SBox
 6 #include "Widgets/Text/STextBlock.h"                                    //文本块部件
 7 #include "Widgets/SOverlay.h"                                            //布局控件
 8 #include "Widgets/Input/SEditableTextBox.h"                        //输入框部件
 9 #include "Widgets/Images/SImage.h"                                    //图片控件
10 
11 #include "Data/SlAiDataHandle.h"
12 
13 
14 
15 BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
16 void SSlAiNewGameWidget::Construct(const FArguments& InArgs)
17 {
18     //获取MenuStyle
19     MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");
20 
21     ChildSlot
22     [
23         SNew(SBox)
24         .WidthOverride(500.f)
25         .HeightOverride(100.f)
26         [
27             SNew(SOverlay)
28 
29             +SOverlay    ::Slot()            //添加按钮图片
30             .HAlign(HAlign_Fill)
31             .VAlign(VAlign_Fill)
32             [
33                 SNew(SImage)
34                 .Image(&MenuStyle->MenuItemBrush)
35             ]
36             
37             +SOverlay::Slot()            //添加按钮文字
38             .HAlign(HAlign_Left)
39             .VAlign(VAlign_Center)
40             .Padding(FMargin(20.f, 0.f, 0.f, 0.f))            //FMargin偏移方式为:左上右下
41             [
42                 SNew(STextBlock)
43                 .Font(MenuStyle->Font_40)
44                 .Text(NSLOCTEXT("SlAiMenu", "NewGame", "NewGame"))
45             ]
46 
47             +SOverlay::Slot()            //添加输入框
48             .HAlign(HAlign_Right)
49             .VAlign(VAlign_Center)
50             .Padding(FMargin(0.f, 0.f, 20.f, 0.f))
51             [
52                 SNew(SBox)
53                 .WidthOverride(300.f)
54                 .HeightOverride(60.f)
55                 [
56                     SAssignNew(EditTextBox, SEditableTextBox)
57                     .HintText(NSLOCTEXT("SlAiMenu", "RecordNameHint", "Input Record Name!"))
58                     .Font(MenuStyle->Font_30)
59                 ]
60             ]
61         ]
62     ];
63 }
64 END_SLATE_FUNCTION_BUILD_OPTIMIZATION
65 
66 bool SSlAiNewGameWidget::AllowEnterGame()
67 {
68     //获取输入的新存档名
69     FText InputText = EditTextBox->GetText();
70     
71     //文字是否为空
72     if (InputText.ToString().IsEmpty())            //ToString 可以将 FText 转换为 FString
73     {
74         return false;
75     }
76     else
77     {
78         for (TArray<FString>::TIterator It(SlAiDataHandle::Get()->RecordDataList); It; It++)
79         {
80             if ((*It).Equals(InputText.ToString()))                //Equals 测试字符串是否与参数字符串相等
81             {
82                 //设置 TextBox 为空
83                 EditTextBox->SetText(FText::FromString(""));
84                 //修改Hint为存档名重复
85                 EditTextBox->SetHintText(NSLOCTEXT("SlAiMenu", "NameRepeatedHint", "Record Name Repeated!"));
86                 return false;
87             }
88         }
89     }
90     //保存新的存档名
91     SlAiDataHandle::Get()->RecordName = InputText.ToString();
92 
93     return true;
94 }

 

 

D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Public\UI\Widget\SSlAiChooseRecordWidget.h

 1 #include "CoreMinimal.h"
 2 #include "Widgets/SCompoundWidget.h"
 3 
 4 class STextComboBox;
 5 /**
 6  * 
 7  */
 8 class SLAICOURSE_API SSlAiChooseRecordWidget : public SCompoundWidget
 9 {
10 public:
11     SLATE_BEGIN_ARGS(SSlAiChooseRecordWidget)
12     {}
13     SLATE_END_ARGS()
14 
15     /** Constructs this widget with InArgs */
16         void Construct(const FArguments& InArgs);
17 
18     //更新存档名
19     void UpDateRecordName();
20 
21 private:
22     //获取MenuStyle
23     const struct FSlAiMenuStyle* MenuStyle;
24 
25     //文字下拉菜单指针
26     TSharedPtr<STextComboBox> RecordComboBox;
27 
28     //存放下拉菜单内容的字符串数组
29     TArray<TSharedPtr<FString>> OptionsSoure;
30 
31 };

 

 

D:\UE4 Project\UE26.2\CourseProject\SlAiCourse\Source\SlAiCourse\Private\UI\Widget\SSlAiChooseRecordWidget.cpp

 1 #include "UI/Widget/SSlAiChooseRecordWidget.h"
 2 #include "SlateOptMacros.h"
 3 #include "UI/Style/SlAiStyle.h"
 4 #include "UI/Style/SlAiMenuWidgetStyle.h"
 5 #include "Widgets/Layout/SBox.h"                                        //一版会把SlateWidget的根组件设成SBox
 6 #include "Widgets/Text/STextBlock.h"                                    //文本块部件
 7 #include "Widgets/SOverlay.h"                                            //布局控件
 8 #include "Widgets/Images/SImage.h"                                    //图片控件
 9 #include "Widgets/Input/STextComboBox.h"                        //文字下拉菜单部件
10 #include "Data/SlAiDataHandle.h"
11 
12 BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
13 void SSlAiChooseRecordWidget::Construct(const FArguments& InArgs)
14 {
15     //获取MenuStyle
16     MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");
17 
18     //初始化下拉菜单
19     for (TArray<FString>::TIterator It(SlAiDataHandle::Get()->RecordDataList); It; It++)
20     {
21         OptionsSoure.Add(MakeShareable(new FString(*It)));
22     }
23 
24     ChildSlot
25     [
26         SNew(SBox)
27         .WidthOverride(500.f)
28         .HeightOverride(100.f)
29         [
30             SNew(SOverlay)
31 
32             +SOverlay    ::Slot()            //添加按钮图片
33             .HAlign(HAlign_Fill)
34             .VAlign(VAlign_Fill)
35             [
36                 SNew(SImage)
37                 .Image(&MenuStyle->MenuItemBrush)
38             ]
39 
40             +SOverlay::Slot()            //添加按钮文字
41             .HAlign(HAlign_Left)
42             .VAlign(VAlign_Center)
43             .Padding(FMargin(20.f, 0.f, 0.f, 0.f))            //FMargin偏移方式为:左上右下
44             [
45                 SNew(STextBlock)
46                 .Font(MenuStyle->Font_40)
47                 .Text(NSLOCTEXT("SlAiMenu", "NewGame", "NewGame"))
48             ]
49 
50             +SOverlay::Slot()            //添加选择栏
51             .HAlign(HAlign_Right)
52             .VAlign(VAlign_Center)
53             .Padding(FMargin(0.f, 0.f, 20.f, 0.f))
54             [
55                 SNew(SBox)
56                 .WidthOverride(300.f)
57                 .HeightOverride(60.f)
58                 [
59                     SAssignNew(RecordComboBox, STextComboBox)
60                     .Font(MenuStyle->Font_30)
61                     .OptionsSource(&OptionsSoure)
62 
63                     //SAssignNew(EditTextBox, SEditableTextBox)
64                     //.HintText(NSLOCTEXT("SlAiMenu", "RecordNameHint", "Input Record Name!"))
65                     //.Font(MenuStyle->Font_30)
66                 ]
67             ]
68         ]
69     ];
70 
71     //设置下拉菜单默认的选项
72     RecordComboBox->SetSelectedItem(OptionsSoure[0]);
73 }
74 END_SLATE_FUNCTION_BUILD_OPTIMIZATION
75 
76 void SSlAiChooseRecordWidget::UpDateRecordName()
77 {
78     //GetSelectedItem 返回当前选中的字符串
79     SlAiDataHandle::Get()->RecordName = *RecordComboBox->GetSelectedItem().Get();
80 }

 

 

SlAiDataHandle.h下添加存档名的声明

d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Public\Data\SlAiDataHandle.h

 1 #include "SlAiTypes.h"
 2 #include "CoreMinimal.h"
 3 
 4 
 5 class SLAICOURSE_API SlAiDataHandle
 6 {
 7 public:
 8     SlAiDataHandle();
 9 
10     static void Initialize();
11 
12     static TSharedPtr<SlAiDataHandle> Get();
13 
14     //修改语言
15     void ChangeLocalizationCulture(ECultureTeam Culture);
16     //修改菜单音量大小
17     void ResetMenuVolume(float MusicVol, float SoundVol);
18 
19 public:
20     /**
21     * 这里没有使用 GamePlay 框架的 GameInstance,变量直接写到C++类中除非你主动销毁,否则他会一直存在
22     */
23     //语言状态
24     ECultureTeam CurrentCulture;
25     //音乐状态
26     float MusicVolume;
27     //音效状态
28     float SoundVolume;
29     //存档数据
30     TArray<FString> RecordDataList;
31     //存档名
32     FString RecordName;
33 
34 private:
35     //创建单例
36     static TSharedRef<SlAiDataHandle> Create();
37 
38     //根据enum类型获取字符串(该方法只能用于UENUM()反射后的枚举,普通枚举不能这样搞)
39     template<typename TEnum>
40     FString GetEnumValueAsString(const FString& Name, TEnum Value);
41 
42     //根据字符串获取enum值(该方法只能用于UENUM()反射后的枚举,普通枚举不能这样搞)
43     template<typename TEnum>
44     TEnum GetEnumValueFromString(const FString& Name, FString Value);
45 
46     //初始化存档数据
47     void InitRecordData();
48 
49 private:
50     static TSharedPtr<SlAiDataHandle> DataInstance;
51 };

 

 对RecordName初始化 

d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Private\Data\SlAiDataHandle.cpp

  1 #include "Data/SlAiDataHandle.h"
  2 #include "Internationalization/Internationalization.h"
  3 #include "Data/SlAiSingleton.h"
  4 #include "Data/SlAiJsonHandle.h"
  5 #include "Common/SlAiHelper.h"
  6 
  7 TSharedPtr<SlAiDataHandle> SlAiDataHandle::DataInstance = NULL;
  8 
  9 SlAiDataHandle::SlAiDataHandle()
 10 {
 11     ////初始化中文
 12     //CurrentCulture = ECultureTeam::ZH;
 13     ////初始化音乐
 14     //MusicVolume = 0.5f;
 15     ////初始化音效
 16     //SoundVolume = 0.5f;
 17 
 18     //初始化存档数据
 19     InitRecordData();
 20 }
 21 
 22 void SlAiDataHandle::Initialize()
 23 {
 24     if (!DataInstance.IsValid())
 25     {
 26         DataInstance = Create();
 27     }
 28 }
 29 
 30 TSharedPtr<SlAiDataHandle> SlAiDataHandle::Get()
 31 {
 32     Initialize();
 33     return DataInstance;
 34 }
 35 
 36 TSharedRef<SlAiDataHandle> SlAiDataHandle::Create()
 37 {
 38     /**
 39     *MakeShareable 可以用来创建共享指针和共享引用
 40     */
 41     TSharedRef<SlAiDataHandle> DataRef = MakeShareable(new SlAiDataHandle());
 42     return DataRef;
 43 }
 44 
 45 void SlAiDataHandle::ChangeLocalizationCulture(ECultureTeam Culture)
 46 {
 47     switch (Culture)
 48     {
 49     case ECultureTeam::EN:
 50         FInternationalization::Get().SetCurrentCulture(TEXT("en"));
 51         break;
 52     case ECultureTeam::ZH:
 53         FInternationalization::Get().SetCurrentCulture(TEXT("zh"));
 54         break;
 55     }
 56     //赋值
 57     CurrentCulture = Culture;
 58     /*
 59     更新存档数据*/
 60     SlAiSingleton<SlAiJsonHandle>::Get()->UpdateRecordData(GetEnumValueAsString<ECultureTeam>(FString("ECultureTeam"), CurrentCulture), MusicVolume, SoundVolume, &RecordDataList);
 61 }
 62 
 63 void SlAiDataHandle::ResetMenuVolume(float MusicVol, float SoundVol)
 64 {
 65     if (MusicVol > 0)
 66     {
 67         MusicVolume = MusicVol;
 68     }
 69     if (SoundVol > 0)
 70     {
 71         SoundVolume = SoundVol;
 72     }
 73     /*
 74     更新存档数据*/
 75     SlAiSingleton<SlAiJsonHandle>::Get()->UpdateRecordData(GetEnumValueAsString<ECultureTeam>(FString("ECultureTeam"), CurrentCulture), MusicVolume, SoundVolume, &RecordDataList);
 76 }
 77 
 78 //根据枚举值返回字符串
 79 template<typename TEnum>
 80 FString SlAiDataHandle::GetEnumValueAsString(const FString& Name, TEnum Value)
 81 {
 82     //通过UE4的FindObject寻找所有ANY_PACKAGE反射到的Name,寻找到后实例化后返回
 83     const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *Name, true);
 84 
 85     if (!EnumPtr)
 86     {
 87         return FString("InValid");
 88     }
 89     return EnumPtr->GetEnumName((int32)Value);
 90 }
 91 
 92 //根据字符串返回枚举值
 93 template<typename TEnum>
 94 TEnum SlAiDataHandle::GetEnumValueFromString(const FString& Name, FString Value)
 95 {
 96     const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *Name, true);
 97 
 98     if (!EnumPtr)
 99     {
100         return TEnum(0);
101     }
102     return (TEnum)EnumPtr->GetIndexByName(FName(*FString(Value)));
103 }
104 
105 void SlAiDataHandle::InitRecordData()
106 {
107     //获取语言
108     FString Culture;
109 
110     //使用单例读取存档数据
111     SlAiSingleton<SlAiJsonHandle>::Get()->RecordDataJsonRead(Culture, MusicVolume, SoundVolume, RecordDataList);
112 
113     //初始化语言
114     ChangeLocalizationCulture(GetEnumValueFromString<ECultureTeam>(FString("ECultureTeam"), Culture));
115 
116     RecordName = FString("");
117 }

 

 

在主菜单组件中调用,这里只调用了 SSlAiChooseRecordWidget 用作测试,也可以将 SSlAiNewGameWidget 添加到这里测试

d:\ue4 project\ue26.2\courseproject\slaicourse\Source\SlAiCourse\Private\UI\Widget\SSlAiMenuWidget.cpp

  1 #include "SlateOptMacros.h"
  2 #include "Common/SlAiHelper.h"
  3 #include "Data/SlAiDataHandle.h"
  4 #include "Widgets/Layout/SBox.h"                                        //一版会把SlateWidget的根组件设成SBox
  5 #include "Widgets/Images/SImage.h"
  6 #include "Widgets/Text/STextBlock.h"
  7 #include "Widgets/SBoxPanel.h"
  8 #include "UI/Style/SlAiStyle.h"
  9 #include "UI/Style/SlAiMenuWidgetStyle.h"
 10 #include "UI/Widget/SSlAiMenuWidget.h"
 11 #include "UI/Widget/SSlAiGameOptionWidget.h"
 12 #include "UI/Widget/SSlAiMenuItemWidget.h"
 13 #include "UI/Widget/SSlAiNewGameWidget.h"
 14 #include "UI/Widget/SSlAiChooseRecordWidget.h"
 15 
 16 
 17 
 18 BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
 19 void SSlAiMenuWidget::Construct(const FArguments& InArgs)
 20 {
 21     //获取MenuStyle
 22     MenuStyle = &SlAiStyle::Get().GetWidgetStyle<FSlAiMenuStyle>("BPSlAiMenuStyle");
 23     /**
 24     *切换语言
 25     //FInternationalization::Get().SetCurrentCulture(TEXT("en"));
 26     //FInternationalization::Get().SetCurrentCulture(TEXT("ch"));
 27     */
 28     //转换为中文
 29     SlAiDataHandle::Get()->ChangeLocalizationCulture(ECultureTeam::ZH);
 30 
 31     ChildSlot
 32     [
 33         /**
 34         *没有Slot,没有Slot要么不能插入子组件,要么只能插入一个子组件,SizeBox 只能插入一个子组件
 35         */
 36         SAssignNew(RootSizeBox, SBox)
 37         [
 38             SNew(SOverlay)
 39 
 40             +SOverlay::Slot()                                        //主菜单背景
 41                 .HAlign(HAlign_Fill)
 42                 .VAlign(VAlign_Fill)
 43                 .Padding(FMargin(0.f, 50.f, 0.f, 0.f))        //FMargin 间隔(左 上 右 下)
 44                 [
 45                     SNew(SImage)
 46                     .Image(&MenuStyle->MenuBackgroundBrush)
 47                 ]
 48 
 49             +SOverlay::Slot()                                        //菜单左侧图片
 50                 .HAlign(HAlign_Left)
 51                 .VAlign(VAlign_Center)
 52                 .Padding(FMargin(0.f, 25.f, 0.f, 0.f))
 53                 [
 54                     SNew(SImage).Image(&MenuStyle->LeftIconBrush)
 55                 ]
 56 
 57             +SOverlay::Slot()                                        //菜单右侧图片
 58                 .HAlign(HAlign_Right)
 59                 .VAlign(VAlign_Center)
 60                 .Padding(FMargin(0.f, 25.f, 0.f, 0.f))
 61                 [
 62                     SNew(SImage).Image(&MenuStyle->RightIconBrush)
 63                 ]
 64 
 65             +SOverlay::Slot()                                        //菜单标题图片
 66                 .HAlign(HAlign_Center)
 67                 .VAlign(VAlign_Top)
 68                 [
 69                     SNew(SBox)
 70                     .WidthOverride(400.f)
 71                     .HeightOverride(100.f)
 72                     [
 73                         SNew(SBorder)
 74                         .BorderImage(&MenuStyle->TitleBorderBrush)
 75                         .HAlign(HAlign_Center)
 76                         .VAlign(VAlign_Center)
 77                         [
 78                             SAssignNew(TitleText, STextBlock)
 79                             .Font(SlAiStyle::Get().GetFontStyle("MenuItemFort"))
 80                             .Text(NSLOCTEXT("SlAiMenu", "Menu", "Menu"))
 81                             .Font(MenuStyle->Font_60)
 82                         ]
 83                     ]
 84                 ]
 85 
 86             +SOverlay::Slot()                            //菜单按钮组件
 87                 .HAlign(HAlign_Center)
 88                 .VAlign(VAlign_Top)
 89                 .Padding(FMargin(0.f, 130.f, 0.f, 0.f))
 90                 [
 91                     //菜单组件创建到这里
 92                     SAssignNew(ContentBox, SVerticalBox)
 93                 ]
 94         ]
 95     ];
 96 
 97     /**
 98     * RootSizeBox在生成的时候没有设置他的宽和高,这里设置下
 99     */
100     RootSizeBox->SetWidthOverride(600.f);
101     RootSizeBox->SetHeightOverride(510.f);
102 
103     ContentBox->AddSlot()
104     [
105             SNew(SSlAiChooseRecordWidget)
106     ];
107 }
108 
109 END_SLATE_FUNCTION_BUILD_OPTIMIZATION
110 
111 void SSlAiMenuWidget::MenuItemOnClicked(EMenuItem::Type ItemType)
112 {
113     //SlAiHelper::Debug(FString("TEXT"), 5.f);
114 }
115 
116 void SSlAiMenuWidget::ChangeCulture(ECultureTeam Culture)
117 {
118     SlAiDataHandle::Get()->ChangeLocalizationCulture(Culture);
119 }
120 
121 void SSlAiMenuWidget::ChangeVolume(const float MusicVolume, const float SoundVolume)
122 {
123     SlAiDataHandle::Get()->ResetMenuVolume(MusicVolume, SoundVolume);
124 }

 

 

 

 

 

 

===========================================================================================================================================

 

 

 

 

 

 

 

 

 

 

 

 

 ………………

posted @ 2021-09-03 18:18  索智源  阅读(732)  评论(0编辑  收藏  举报