天天看點

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【導圖】:

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【前言】:

奈何水準有限,本篇有多處扯淡的環節,謹慎參考。

【1.】:視訊教程

迪迪老濕哪——UE4純C++與Slate開發沙盒遊戲​ke.qq.com

【2.】:UE4 C++基礎系列

  • 【UE4】C++基礎【00】——通俗易懂 用藍圖來學習 C++ 基礎知識
  • 【UE4】C++基礎【01】——預設代碼扒拉拉(初學者向)
  • 【UE4】C++基礎【02】——添加Slate至視窗

【3.】:UI實作原理:

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【4.】:常混淆關鍵詞梳理

常混淆的關鍵詞,Slate、UMG、UI、HUD、Widget,前言中先梳理一下。

  • Slate ——
    • 定義——Slate是完全自定義、與平台無關的使用者界面架構。簡而言之, Slate是跨平台的UI架構
    • 功能實作——
      • 可以用來做應用程式Application的UI(如UE4 Editor 獨立exe可執行程式)
      • 工具架Toolbar的UI
      • 更可以做遊戲當中的UI (Slate代碼建立 VS UMG可視化建立)
  • UMG(Unreal Motion Graphics UI Designer) ——它是 工具 ,一個可視化的UI建立工具,就是WidgetBlueprint的那個Designer環境(Designer負責可視化、Graph負責控件事件定義)
    • 作用——可用來建立UI元素,如HUD、菜單等
    • 核心——Widgets控件
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
  • UI(UserInterface) ——使用者界面
    • 含義——菜單和其他互動元素,像Menu主菜單、Pause暫停菜單、NPC頭頂的對話框等。
  • HUD(Head Up Display) ——
    • 典故——來源于飛機飛行員,指擡頭就能看到儀表盤上飛機的飛行資料。
    • 含義——遊戲期間(Runtime)在螢幕上覆寫的狀态和資訊
    • 目的——告知玩家目前遊戲狀态,如分數、生命值、遊戲時間等。
    • 定義——HUD通常不可互動,意味着玩家不能單擊HUD的元素
  • Widget ——控件
    • 含義 ——它們是一系列預先制作的函數
    • 作用 ——可用于建構界面(如Button按鈕、Slider滑塊、ProgressBar進度條、Vertical/Horizontal Box 水準/豎直框。
    • 大環境 ——這些Widget控件在專門的控件藍圖(UserInterface-> WidgetBlueprint )中編輯。它使用兩個頁籤進行構造
      • Designer ——控件可視化布局,位置、旋轉、縮放、父子等
      • Graph ——實作控件背後的功能,如細節面闆中的Events事件,像Button的OnClicked、Hovered事件等。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【5.】:小貼士

我感覺初學者學C++就是個先不斷找尋

對應英文語句和各種符号的意思

的過程,跟閱讀了解差不多。

我覺得學代碼應該分為這些階段:

  • 新手
    • Happiness——知道這麼寫能不報錯,哈哈哈哈,有一定的獎勵回報以支撐頭發繼續戰鬥下去。(What?)
    • Effect——簡單知道這麼寫能起什麼作用(How?)
  • 高手
    • Benifit——深入了解引擎為什麼要這麼寫,有什麼好處。(Why?)

在學習期間肯定有很多不會的地方,可以按以下方式查詢。

  1. VS中滑鼠懸浮語句出Tooltip提示框快速檢視對應意思。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

2.網頁端虛幻官方C++ API Reference (或像上面滑鼠Hover的時候,點選SearchOnline,會自動用Bing搜尋關鍵詞,跟内容浏覽器資源右鍵View Documentation/See Full Documentation差不多)

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

3.深入了解的話,就右鍵PeekDefinations在目前文檔内出小視窗快速浏覽或 GoToDefinition到源檔案檢視相應代碼。

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

一、 預備工作

【1.1】建立基礎C++類(GameMode、PlayerController、HUD)

  1. 建立地圖—— Content->Map->建立

    MenuMap

  2. 設定項目預設地圖——Project Settings ->Maps & Modes 設定

    MenuMap

    為項目預設地圖
  3. 建立C++ GameModeBase 為

    ShitGameMode

    1. 確定 Public—— 頭檔案public、源檔案private
    2. Public路徑後添加

      /GamePlay

      以将這個

      ShitGameMode

      放在 GamePlay檔案夾下,規整一點(如果報錯不能生成檔案,後期VS處理)
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

4. 建立 PlayerController 為

ShitController

,同樣Public

5. 建立 HUD (跟UI一樣放在螢幕上,但是不用手動AddToViewport)為

ShitHUD

,同樣為Public。

  • GameController
  • GameMode
  • HUD

如若出現報錯,請按照提示在cpp中添加檔案路徑字首:UE4添加C++類失敗 如何解決?

【1.2】世界設定GameMode為新建立自定義的GameMode類

  • ShitGameMode
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

二、VS代碼編輯器配置GameMode

【2.1】給ProjectName.Build.cs添加Slate、SlateCore子產品

當然内部原理更複雜,我等菜鳥簡單了解一下具體的功能即可,後期深入再了解原理。

  • Unreal Build Tool (UBT)——負責 各個子產品的編譯 并處理 各子產品之間的依賴關系,Build.cs和Target.cs就是服務于UBT的。Build.cs中包含了定義的子產品的依賴關系、額外的庫、路徑等資訊,這些檔案被編譯成dll動态連結庫檔案,并通過單一的exe可執行檔案進行加載。
  • Unreal Header Tool (UHT)——C++代碼解析工具
    • 搜集帶U的,如UCLASS()、UPROPERTY() 生成反射資料并注入到 GENERATED_BODY()中。

籃子悠悠:UE4 C++基礎教程 - 工程目錄結構​zhuanlan.zhihu.com

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

如果我們要使用Slate UI 我們隻需要Uncomment取消注解就可以了。

新添加格式為字元串,名字為Slate、SlateCore,到 私有從屬組塊名中。

PrivateSlate語句行,

Ctrl+K,Ctrl+U(Uncomment)

(Ctrl+C(comment))

PrivateDependencyModuleNames.AddRange(new string[] {"Slate"、"SlateCore"});
           
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【2.2】使用VAssistX插件在Gamemode.h頭檔案中新Declare構造函數

  • VAssistX
    • 快速追蹤,
      • Alt+G ——Declaration和Definition的快速跳轉;
      • Alt+O ——cpp 和 h 檔案快速切換
    • 快速建立,添加成員變量的Set/Get方法,如構造函數,CreateImplementation
      • Alt+C (自定義)——CreateImplementation 快速建立實作,直接在頭檔案函數聲明(Declaration)處快捷鍵,然後就跳轉到了源檔案中,并自動寫好函數實作語句(Definition)。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【2.3】

GENERATED_BODY()

GENERATED_UCLASS_BODY()

的差別

  • _Body()

    • 辨別的類的成員預設是Private的
    • 辨別的類 需要聲明 無參數的構造函數 (Public:如AxxxActor)
  • _

    UCLASS_Body()

    • 可以不聲明構造函數(如果要實作構造函數需要加上

      const FObjectInitializer&ObjectInitializer:Super(ObjectInitializer)

      參數 (ObjectInitializer,對象構造器/對象初始化操作)

我們之前學過Super()的作用就是調用這個函數之前會先調用父類中的函數。

預設的是

GENERATED_BODY()

,本節隻是簡單了解一下二者差別。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【2.4】GameMode源檔案中#include HUD和Controller的頭檔案

  • 我們之前說過h是上司,外面接活,就是#include一堆引擎的東西,啥架構、反射生成啦這些玩意兒。
  • cpp是員工,給上司幹活,#include一堆我們自己建立的上司。

如Gamemode cpp員工要#include自身Gamemode上司,還有其他兩個上司。注意路徑,Gameplay或UI檔案夾,否則 #include下面一堆姨媽紅。

//ShitGameMode.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "GamePlay/ShitGameMode.h"
#include "GamePlay/ShitController.h"
#include "UI/HUD/ShitHUD.h"

AShitGameMode::AShitGameMode()
{

}
           

【2.5】GameMode cpp 源檔案中 補充構造函數定義,細化GameMode配置

說明:

  • ::

    作用域限定符(範圍解析運算符)
    。類外實作函數定義 (如藍圖學習C++ 【8.1】中類成員函數的類内類外定義 和【8.2】中構造函數的聲明與定義)
  • StaticClass() 是UE4引擎自己通過反射建立的檔案下面的一個函數,運作時可以傳回這個類的UClass對象。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
  • 文法:類名Class=繼承類名::StaticClass();
  • 如 HUDClass=AShitHUD::StaticClass();

代碼中的

=

等号其實就跟在編輯器ComboBox中選枚舉一樣,像完善GameMode詳細參數,如HUD、Controller這些。我們在代碼中直接寫死,不讓在編輯器中枚舉選了。

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
// ShitGameMode.cpp

#include "GamePlay/ShitGameMode.h"
#include "GamePlay/ShitController.h"
#include "UI/HUD/ShitHUD.h"

AShitGameMode::AShitGameMode()
{
	PlayerControllerClass = AShitController::StaticClass();
	HUDClass = AShitHUD::StaticClass();
}


           

【2.6】Build檢驗

編輯器中看到在VS中定義的GameMode的屬性都傳過來了,且不可改動

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

三、VS代碼編輯器配置PlayerController

【3.1】ShitController 構造函數定義聲明

  1. 來到ShitController 頭檔案。
  2. 跟GameMode一樣頭檔案中public聲明構造函數
  3. 再滑鼠懸浮構造函數處 Alt+C通過VAssistX插件在cpp中快速定義構造函數基本文法,即CreateImplementation建立聲明的實作。
// ShitController.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "ShitController.generated.h"

/**
 * 
 */
UCLASS()
class TESTGAME_API AShitController : public APlayerController
{
    GENERATED_BODY()

public:AShitController(); //在此Alt+C
};
           
//ShitController.cpp

#include "GamePlay/ShitController.h"

AShitController::AShitController() //Alt+C 結果
{

}
           

【3.2】ShitController中詳細定義函數

【1】

bShowMouseCursor=true;

顯示滑鼠

  • 藍圖一般是關卡藍圖中getcontroller、ShowMouse變量、打勾不打勾 或PlayerController藍圖中勾選顯示滑鼠。( 構造函數中寫的這個就跟Controller藍圖中Class Settings勾選是一樣的)
  • C++直接b布爾類型變量、ShowMouse變量、=True/False 是否啟用
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【2】設定隻接受滑鼠輸入并将滑鼠鎖在視窗内

  1. 頭檔案中跟預設代碼一樣聲明 BeginPlay初始函數 虛函數——

    virtual void BeginPlay() override;

  2. 一樣Alt+C CreateImplementation建立函數聲明。
  3. 源檔案中定義鎖定滑鼠在視窗内
  • FInputModeUIOnly—— 用于設定僅允許UI響應使用者輸入的輸入模式的資料結構
// Fill out your copyright notice in the Description page of Project Settings.


#include "GamePlay/ShitController.h"

AShitController::AShitController()
{
	bShowMouseCursor = true;
}

void AShitController::BeginPlay()
{
	FInputModeUIOnly InputMode;
	InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::LockAlways);
	SetInputMode(InputMode);
}
           
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【3.3】Build檢驗

  1. VS Game Build
  2. Hot 熱更新過來可以看到定義的Class都過來了

然後Standalone Game獨立遊戲模式 Alt+P 運作檢驗結果:

看到滑鼠是顯示出來的且卡在視窗内。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

四、VS代碼編輯器配置SlateWidget

【4.1】建立兩個SlateWidget

【操作】:
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
【注意事項】:
  • 需要注意的是SlateWidget并不會在ContentBrowser中出現,包括檔案夾,它隻會在VS中出現。(我還各種Build、Rebuild、重新開機測試,結果是真的沒有, 大家别費那個勁兒在Content Browser中找了
  • UE4 C++基礎 篇中我們講到過UE4采用Pascal命名法,S字首代表SlateWidget。比如我們藍圖建立了一個名為ShitWidget的SlateWidget,VS中會變成SSlateWidget.h/.cpp。
  • HUD是不帶S字首的,SlateWidget才帶S字首,注意一下。

【4.2】HUD基礎代碼配置

  • 跟上面GameMode和Controller一樣,在HUD 頭檔案中同樣public聲明,Alt+C源檔案定義構造函數。
  • ShitHUD cpp源檔案中#include 引用
    • SShitMenuHUDWidget.h頭檔案。
    • SlateBasics.h頭檔案。(否則會報錯)
// ShitHUD.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "ShitHUD.generated.h"

/**
 * 
 */
UCLASS()
class TESTGAME_API AShitHUD : public AHUD
{
	GENERATED_BODY()

public:
		AShitHUD(); //聲明構造函數
}
           
//ShitHUD.cpp
#include "UI/HUD/ShitHUD.h"
#include "UI/Widget/SShitMenuHUDWidget.h"
#include "SlateBasics.h"

AShitHUD::AShitHUD()
{ };
           

【4.3】綁定Widget至HUD并添加到GameViewport遊戲視窗中。

參考官方文檔——在遊戲中使用Slate

【1.】:

頭檔案聲明指針

// ShitHUD.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "ShitHUD.generated.h"

/**
 * 
 */
UCLASS()
class TESTGAME_API AShitHUD : public AHUD
{
	GENERATED_BODY()

public:
		AShitHUD();

		TSharedPtr<class SShitMenuHUDWidget>MenuHUDWidget;
	
};
           

上面的

TSharedPtr<class SShitMenuHUDWidget>MenuHUDWidget;

跟下面的藍圖差不多。

  • TSharedPtr 聲明共享指針。
  • 指針類為

    ShitMenuHUDWidget

    (用UMG建立的自定義UI,繼承自UserWidget)
  • 指針名為

    MenuHUDWidget

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
  • TSharedPtr——等同于在藍圖細節面闆中的變量欄建立一個變量(指針變量)
  • ToSharedRef()——将指針指的Class類調用過來。
【2.】:

源檔案定義指針

// ShitHUD.cpp


#include "UI/HUD/ShitHUD.h"
#include "UI/Widget/SShitMenuHUDWidget.h"
#include "SlateBasics.h"

AShitHUD::AShitHUD()
{
	if (GEngine && GEngine->GameViewport)
  {
		SAssignNew(MenuHUDWidget, SShitMenuHUDWidget);

		GEngine->GameViewport->AddViewportWidgetContent(
SNew(SWeakWidget).PossiblyNullContent(MenuHUDWidget.ToSharedRef())
);
   }
}
           
【解釋說明】:
  • 【1】if語句
    • && 邏輯與運算符,兩個表達式必須都為true,整個表達式才為true
    • 判斷GEngine和GameViewport是否存在,存在則執行括号中的語句
  • 【2】建立SlateWidget語句
    • SAssignNew為SlateWidget的一種建立方式,要 搭配頭檔案中聲明的指針 一起才管用。
TSharedPtr<class SShitMenuHUDWidget>MenuHUDWidget;
SAssignNew(MenuHUDWidget, SShitMenuHUDWidget);
           

兩種建立方式的差別是:

  • SNew(xxx)
  • SAssign(指針,SlateWidget類名)
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

SNew和SAssignNew

  • 3】添加到遊戲視窗語句
GEngine->GameViewport->AddViewportWidgetContent(
SNew(SWeakWidget).PossiblyNullContent(MenuHUDWidget.ToSharedRef())
);
           
  1. GEngine->GameViewport->AddViewportWidgetContent();

    添加到遊戲視窗(預設代碼 中我們還學過GEngine也是可以在螢幕上Print String列印資訊)
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
  • 為了在遊戲中顯示一個Slate控件,就必須把這個控件添加到遊戲視口(Viewport)中。
    • 重疊的控件會按照Z-Order索引進行排序,大的數置頂在上面,小的數在下面,跟PS的圖層一樣。
  • 遊戲視口GameViewport是GameViewportClient的一個執行個體,可通過使用到遊戲目前 U Engine執行個體的“ G Engine”(Game Engine?)指針通路——

    GEngine->GameViewport

  • GameViewport的AddViewportWidgetContent函數可以将控件添加到視口中。
2.

SNew(SWeakWidget).PossiblyNullContent(MenuHUDWidget.ToSharedRef());

将上面通過SAssignNew建立的SlateWidget添加到視口中
【實作流程】:
  1. PossiblyNullContent(MenuHUDWidget.ToSharedRef()——如果這個指針指向的widget類存在,那就
  2. SNew(SWeakWidget)——把它傳到這個新建立的SWeakWidget SlateWidget中
  3. GEngine->GameViewport->AddViewportWidgetContent(....),将SWeakWidget添加到螢幕上。
【SWeakWidget是什麼】:
  • SWeakWidget 是什麼鬼?——實作一個小部件,該小部件持有指向一個子小部件的弱指針(Weak Pointer)。它封裝一段内容而不擁有它。 可以了解為一種綠綠的暧昧的關系。
    • Tooltip=A,女一号
    • Hovered Widget =B,男一号。
    • Floating Window=C,男二号。
B代碼裡有A,但是A通過C顯示,然而C代碼裡面沒有A。

(哈哈,就好比男一号心裡有女一号,然而女一号要通過跟男二号潛規則才能上位亮相,但是男二号心裡并沒有女一号。那是因為男二号還有很多可潛規則的對象。)

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
【3.】SlateWidget分辨
  • 項目編輯器中 ——
    • 我們在項目編輯器中建立的是 兩個特定SlateWidget類 ,這裡SlateWidgets就代表添加到螢幕上面的那些UserWidget(藍圖)。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
HUD中引入SlateWidget,以添加到GameViewport。
  • VS中 ——
    • 而我們在HUD中通過

      SNew()或SAssignNew()

      建立SlateWidgets,指定我們建立的SlateWidgets以填充至螢幕中。
    • 兩個特定SlateWidgets類 中我們同樣也可以通過

      SNew()或SAssignNew()

      來建立

      SButton

      元件,以在Widgets中添加Button按鈕。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗
SlateWidget中新建立Button、Box等像UMG中的那些Widget控件。
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【4.4】: 解決小Bug

虛幻的Bug真神奇:

  1. 有這種白色棱形問号的,不用思考,肯定是中文的問題,系統語言更改真的有時候能夠解決很多問題的,比如微信定位位址,電腦系統英文會預設用Google打開,中文會預設用騰訊地圖打開。 系統語言改為英文後,就到了第二個編号了,明顯少了一個bug。
  2. 第二個它提示不能夠删除dll動态連結庫,直接關閉VS,然後在ContentBrowser中随便打開一個Class,然後再Build,就好了,編譯成功!虛幻就是這麼地神奇!
combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

【4.5】SlateWidget中引入SButton元件

ShitMenuHUDWidget 源檔案中新引入

SButton.h"

,添加SButton元件。

  • [ ]中括号是重載運算符
  • ChildSlot就是槽,可以放子控件。
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/Widget/SShitMenuHUDWidget.h"
#include "SButton.h"
#include "SlateOptMacros.h"

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SShitMenuHUDWidget::Construct(const FArguments& InArgs)
{
	
	ChildSlot
		[
			SNew(SButton)// 建立一個Button Slate
	];
	
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
           

注意一下這個路徑的問題,開頭我是直接 在HUD cpp源檔案中

#include"SButton.h"

,後來一直報錯,結果檢查到還是路徑的問題呢。個人覺得Build.cs中引入子產品名其實就跟檔案夾定位的意思差不多,Build.cs定一次,一勞永逸,省得在自定義類的源檔案中再多次#include這個檔案夾了。

  • 然後VS中右鍵SButton.h找到它的定義,然後再檔案資料總管中打開,檢視路徑。

是以最終

#include"Widgets/Input/SButton.h"

就解決問題了,因為路徑對了嘛,UE可以找到SButton啦。

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

最終效果:可以看到Button充滿了整個螢幕。不過我們還沒有定義事件,我們下節再定義。

combobox添加下拉内容_【UE4】C++基礎【02】添加Slate至視窗

待續。添加樣式啥的。