下圖為菜單結構,到目前為止已經實作了遊戲設定控件(綠色的部分),還缺少開始遊戲控件,這個部将會開始實作 "輸入存檔名" 與 "選擇存檔" 的部分

首先我們在 UI/Widget 檔案夾下建立兩個 SlateWidget 元件
SlAiNewGameWidget 與 SlAiChooseRecordWidget
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 }
===========================================================================================================================================
………………