原文:Unreal Engine 4 UI Tutorial
作者:Tommy Tran
譯者:Shuchang Liu
在本篇教程,你將學會如何創建,展示和更新一個HUD界面。
在游戲中,開發者使用圖像和文字來展示玩家血條,得分等相關信息,這就是用戶界面(UI)。
你可以在Unreal Engine 4里利用Unreal Motion Graphics(UMG)。UMG允許你通過拖拽按鈕,文本等UI元素來構建UI界面。
在本篇教程,你將學會:
- 創建展示得分和時間的HUD
- 展示HUD
- 當變量值變化時,更新得分和時間顯示
請注意,本篇教程涉及藍圖內容。如果你需要復習有關內容,請查看藍圖教程。
注意:本篇教程只是Unreal Engine 4系列教程的其中一篇:
起步入門
下載示例項目並解壓。進入項目文件夾,雙擊BananaCollector.uproject打開項目。
注意:如果你看到了項目是由較早的引擎版本創建的提示,這很正常(因為引擎經常更新版本)。你可以選擇以拷貝副本的形式打開,也可以直接轉換項目版本打開。
點擊Play開始游戲,控制白色方塊接住掉落的圖形。你可以通過移動鼠標平移方塊。10秒后,圖形會停止掉落。

我們要做的第一件事就是創建HUD展示兩個信息:
- 玩家收集了多少個圖形的計數
- 距離圖形停止掉落的倒計時
其中需要使用到Widgets(控件)。
關於控件
控件是一種提供簡單功能的UI元素。比如,按鈕控件提供了玩家可見可點擊的物體。

控件本身不一定是可視的。比如,網格面板掛件只是用於平均排布子元素。玩家看不見控件本身,但能看到控件的效果。

控件也可以嵌套控件。比如下面是一個自定義控件,它又包含了一個文本控件(名字文本)和文本輸入框控件:

你甚至可以創建一個鋪滿屏幕的控件。比如下面的控件作為一個標題界面鋪滿了屏幕。這個控件所包含了其他UI元素也都為控件。

了解完什么是控件,現在動手創建一個。
創建控件
Content Browser界面進入UI文件夾。點擊Add New按鈕,選擇創建User Interface\Widget Blueprint,將其重名為WBP_HUD。

雙擊WBP_HUD打開UMG UI Designer。
UMG UI Designer
UMG UI Designer由七個主要元素組成:

- Designer:這個區域展示所選控件的外觀。通過長按右鍵移動鼠標拖動面板,滑動滾輪縮放面板。
- Details:展示所選控件的參數
- Palette:可用控件列表
- Hierarchy:當前所使用的控件列表
- Animations:控件能夠基於位置,大小等外觀參數制作動畫效果。該面板展示控件的所有動畫
- Timeline:當你選中動畫時,該面板會展示對應的動畫參數和關鍵幀
- Editor Mode:通過該按鈕可以切換編輯器的Designer和Graph模式。Graph模式的編輯器顯示類似於藍圖的Event Graph。
創建Text控件
Text控件非常適合展示像計數和倒計時這樣的數字信息。
在Palette面板搜索Text控件。通過按住左鍵拖拽控件至Designer面板。

別在意文本內容,等等我們會替換它。
先選中Text控件,在Details面板頂部的文本框輸入CounterText進行重命名。

你可以在Designer面板通過長按左鍵拖拽控件。

你也可以通過左鍵點擊拖拉選中框來調整控件的大小。這樣可以調整控件的包圍框。Unreal引擎不會渲染包圍框之外的內容。

同樣的,你可以通過Details面板輸入數值來修改控件的位置和大小。設置CounterText如下:
- Position X: 200
- Position Y: 50
- Size X: 500
- Size Y: 100

此時文本只占了包圍框很小一部分顯示。

我們可以在Detail面板的Appearance設置調大字體大小。在Font屬性的最右側文本框可以設置字體大小。

將字體大小調成68。

接着我們再在文本框旁添加一個圖標來提升視覺效果。
創建Image控件
Image控件可以讓我們展示像圖標一類的UI圖形。
創建Image控件並將其命名為CounterIcon。將Position X設成75,Position Y設成50,顯示在CounterText左邊。

接着在Details面板的Appearance設置顯示圖片。展開Brush設置,點擊Image字段下拉框,選擇T_Counter。

由於控件與圖片的長寬不一樣,圖片看起來擠壓變形了。

除了手動調整控件大小,我們還可以使用Size To Content選項來調整控件大小。該選項會自動將控件大小調整成圖片大小。
點開Details面板的Slot(Canvas Panel Slot)部分設置,勾選Size To Content 選中框。

控件會適應調整成圖片的大小。

當游戲在不同屏幕尺寸下運行時,UI控件需要根據情況調整顯示位置。為了保持UI的布局,我們可以使用錨點。
錨點
錨點確定了控件位置的相對參考點。控件的錨點默認為其父對象的左上角。所以,當我們在給一個控件設位置時,其實是在設控件相對於錨點的位置。
下圖例子里,每個Image都以一個點作為它們的錨點(距離自身最近的角落點)。

注意看每個Image是怎么與錨點保持相對位置的。合理利用錨點,就可以保證UI元素在不同屏幕尺寸上都保持統一布局。
我們也可以利用錨點來自動調整控件的大小。當錨點多於兩個點或更多時,控件會根據屏幕尺寸調整大小來保持它的相對尺寸。
下圖例子里,灰色長條的錨點為左上角和右上角。

在垂直方向上,灰色長條隨着錨點移動,但尺寸沒有變化。這是因為在Y軸上,控件只有一個錨點(頂部)。然而,在水平方向上,灰色長條是隨着錨點移動而調整尺寸的,因為在X軸上它有兩個錨點。
錨章代表了控件錨點所在位置,只要選中了控件,錨點標志就會展示在界面上。

如圖所示CounterText和CounterIcon的錨點已經在正確的位置上了,無須再做修改。
接着,我們需要再創建Text和Image控件來顯示倒計時。這兩個控件則需要手動將其錨點設置在右上角上。
創建倒計時
創建Text控件並將其命名為TimerText。設置參數如下:
- Position X: 1225
- Position Y: 50
- Size X: 500
- Size Y: 100
- Font Size: 68
- Justification: Align Text Right(文本向右對齊)

接着,通過長按左鍵拖拽錨點標志,將標志從左上角移到右上角,來修改Text錨點。

可以注意到控件位置信息隨着錨點變化,也相應變化了。

創建Image控件並將其命名為TimerIcon。設置參數如下:
- Position X: 1750
- Position Y: 50
- Size To Content: 勾選
- Brush\Image: T_Timer

除了手動調整錨點標志,我們還可以直接使用預設調整錨點。在Details面板點擊Anchors旁邊的下拉框展示預設。選擇第三個預設(帶有右上角小方塊的那個)。


UI布局現在已經設置好了。我們可以通過模擬不同屏幕尺寸來檢查錨點設置是否合適。在Designer面板點擊Screen Size下拉框。

WBP_HUD會根據所選項進行尺寸自適應。下圖是HUD在iPad Air上的顯示效果。可以看到控件的間隔更近了些。

教程下面的章節,你將學會如何顯示WBP_HUD控件。
顯示HUD
點擊Compile並返回到主編輯器。點進Blueprints文件夾,並雙擊打開BP_GameManager。
HUD應該在游戲一啟動就顯示。我們在Event BeginPlay節點實現相應邏輯。
找到Event BeginPlay節點,添加Create Widget節點與最后一個節點相連。這個節點會創建特定控件實例。

點擊Class下拉框,選擇WBP_HUD。

為了顯示HUD,我們還需要Add to Viewport節點。按住左鍵拖拽Return Value引腳到空白處,在彈出菜單中選擇Create Widget進行創建。

讓我們過一遍事件邏輯:
- 一旦Unreal生成BP_GameManager,Restart和SetUpCamera函數就會執行。這些函數會設置一些變量和攝像機。如果你還不知道什么是函數,別擔心。教程后面會有講解。
2.Create Widget節點會創建WBP_HUD實例。
3.Add to Viewport節點顯示WBP_HUD。
點擊Compile節點並回到主編輯器。按下Play在游戲里看看你的新HUD吧。

為了展示計數和倒計時信息,你需要變量記錄相應信息。你可以在BP_GameManager看到這些變量。

為了使用這些變量,需要在WBP_HUD里訪問到BP_GameManager。我們可以通過新建變量存儲BP_GameManager引用來達到目的。
存儲引用
存儲引用可以幫助我們快捷地獲取特定對象實例。
想象現在有一個裝着球的盒子。如果你想要找到這顆球,那是非常簡單,因為只存在一個盒子。

現在,再想象有一百個盒子,只有一個盒子裝着球。你就得遍歷所有的盒子才能找到那顆球。

每次你想拿到那顆球,你都得做這樣的一個操作。這樣很快就會導致性能問題。
通過引用,你就能追蹤到裝有球的盒子。這樣,就不用再做遍歷操作了。

創建變量
打開WBP_HUD切換到Graph模式。

在My Blueprint頁簽創建新變量GameManager。
在Details面板點擊Variable Type下拉框。搜索BP_GameManager,並選擇BP Game Manager\Object Reference。

設置引用
點擊Compile並打開BP_GameManager。
找到Create Widget節點,在Return Value引腳按住左鍵拖拽到空白處,選中彈出菜單的Set Game Manager。
隨后,將Add to Viewport節點與Set Game Manager節點相連。

注意:通過在雙擊連線,可以添加變更道路節點。長按左鍵拖拽變更道路節點就可以改變連線的走向。
接着,創建Self節點並與Set Game Manager節點左邊的引腳相連。Self節點通過Get a reference to self菜單項可以獲取到。

現在,當WBP_HUD創建完后,它可以拿到BP_GameManager的引用。
教程下一部分,你將學習如何通過函數更新控件。
函數
在藍圖中,函數是類似於事件圖表的另一種圖表。不同於事件圖表,我們可以通過節點調用函數。你可能會問,這么做的意義又是什么呢?

組織性
使用函數的一大原因就是方便組織。通過使用函數,我們可以將多個節點要做的事合成一個節點來完成。
看下BP_GameManager的Event BeginPlay部分邏輯,這里有兩個函數:Restart和SetUpCamera。

如果不用函數,那這部分的邏輯是這樣的:

可以看到,使用函數,整體邏輯看起來更簡潔了。
重用性
使用函數的另一大原因是方便重用。比如,你想要重置計數和倒計時,通過Restart函數就能實現。

每次你想重置變量時,就不需要再創建那么多節點了。
現在弄清楚了函數的用處,我們就使用函數來更新CounterText控件吧。
更新控件
藍圖默認是訪問不到Text控件的。這意味着我們不能設置文本。幸運地是這不難解決。
點擊Compile並打開WBP_HUD。將界面切換到Designer模式。
選中CounterText並在Details面板的頂部,勾選Is Variable勾選框。

現在,我們已經可以更新CounterText了。下一步要做的是創建函數來更新文本。
創建更新函數
將界面切換成Graph模式,點擊My Blueprint頁簽,點擊Functions區域的+號。

這樣會創建出一個新函數,並會自動跳轉到它的圖表界面。這里將函數重命名為UpdateCounterText。
圖表上默認會有一個入口節點。一旦函數被觸發,就是從該節點開始執行。

為了讓CounterText顯示ShapesCollected變量,我們需要手動連接兩者。
將GameManager變量拖拽至圖表。左鍵拖拽引腳到空白處,從彈出菜單中選擇Get Shapes Collected節點。

要設置文本,我們需要用到SetText (Text)節點。拖拽CounterText變量至圖表。左鍵拖拽引腳到空白處,從彈出菜單中選擇SetText (Text)節點。

SetText (Text)節點只接受Text類型的輸入,而ShapesCollected變量卻是Integer類型變量。幸運地是,當用戶用Integer去連接Text輸入時,會自動進行裝換。
連接ShapesCollected變量和Set Text (Text)節點的In Text引腳,Unreal會自動創建插入ToText (int)節點。

再來看下事件的順序:
- 當外部調用UpdateCounterText,函數會從BP_GameManager引用獲取ShapesCollected變量
- ToText (int)節點將ShapesCollected變量轉換成Text類型
- SetText (Text)將來自ToText (int)的值設置給CounterText控件
接下來我們要實現,玩家每收集一個圖形,就調用一次UpdateCounterText。
調用更新函數
在ShapesCollected變量每次自增加一時,調用UpdateCounterText是最合適的。我已經先創建好了IncrementShapesCollected函數用於累加計數。每次玩家角色觸碰到掉落的圖形,就會調用該函數。

點擊Compile,並返回到BP_GameManager。
在調用UpdateCounterText之前,你還需要獲得WBP_HUD引用,看看你能不能自己存儲獲得引用!
- 找到你創建並顯示WBP_HUD的地方
- 左鍵拖拽Create Widget節點的Return Value引腳
- 在空白處釋放左鍵,從彈出菜單中選中Promote to variable
- 將新創建的節點與最后一個節點相連
創建好節點,將其重命名為HUDWidget。

接着,拖拽Set HUDWidget節點右側引腳至空白處,添加UpdateCounterText節點。這樣游戲一開始,CounterText就會顯示ShapesCollected變量值。

隨后在My Blueprint面板的Functions區域,雙擊IncrementShapesCollected打開圖表。

拖拽HUDWidget至圖表,左鍵拖拽引腳至空白處,從彈出菜單中添加UpdateCounterText節點並如下圖連接:

現在,只要IncrementShapesCollected執行調用,都會累加ShapesCollected並調用UpdateCounterText函數。該函數負責將CounterText更新成ShapesCollected的值。
點擊Compile並關閉BP_GameManager。點擊Play運行游戲收集圖形並觀察CounterText變化。

接着,我們會使用另一種叫綁定的方法更新TimerText控件。
綁定
綁定允許我們自動更新控件的特定參數。可以進行綁定的參數,都會有個Bind下拉框。

我們能將控件的參數與某個函數或者變量進行綁定。綁定會持續地從函數或變量中獲得返回值,並將其賦值給參數。

你可能奇怪那為什么前面不使用綁定。由於每幀恆定更新,綁定並不是一種很高效率的做法。這意味着即使參數沒有變化,每幀也會浪費時間進行參數更新。相比前面的做法,則只會在數值發生變化時才更新控件。
這么說來,綁定適用於像倒計時這類更新頻繁的UI元素。接着試試給TimerText創建綁定吧。
創建綁定
打開WBP_HUD並切換到Designer模式。
選中TimerText,留意Details面板的Content部分。可以看到Text參數是可綁定的。點擊Bind下拉框並點擊Create Binding。

這樣會創建新函數並跳轉至它的圖表。將函數重命名為UpdateTimerText。
這個函數會有個Text類型Return Value引腳的Return節點。TimerText會顯示這個引腳所獲得任何文本。

拖拽GameManager至圖表,並獲取TimeRemaining變量。
連接TimeRemaining變量與Return節點的Return Value引腳。像之前一樣,Unreal會自動創建插入轉換節點。

小結:
- 綁定會持續調用UpdateTimerText函數
- 函數會從BP_GameManager獲取TimeRemaining變量值
- ToText (float)節點會將TimeRemaining變量值轉換成Text類型
- 轉換值會通過Return節點輸出
HUD的邏輯至此全部完成。點擊Compile並關閉WBP_HUD。按下Play運行游戲看下最終效果。

后續學習
你可以在這里下載完整項目。
現在你已經了解了UMG的基礎知識,構建更復雜點的界面也不再是難事。多多嘗試其他控件吧。
如果想了解更多控件的用處,請前往Unreal引擎文檔的控件類型參考頁。
如果你還想繼續學習引擎其他內容,點擊下篇教程,將教你如何整合已學知識,制作一個簡單游戲!