• Unreal Engine 4 系列教程 Part 4:UI教程


    原文:Unreal Engine 4 UI Tutorial
    作者:Tommy Tran
    译者:Shuchang Liu

    在本篇教程,你将学会如何创建,展示和更新一个HUD界面。

    在游戏中,开发者使用图像和文字来展示玩家血条,得分等相关信息,这就是用户界面(UI)。

    你可以在Unreal Engine 4里利用Unreal Motion Graphics(UMG)。UMG允许你通过拖拽按钮,文本等UI元素来构建UI界面。

    在本篇教程,你将学会:

    1. 创建展示得分和时间的HUD
    2. 展示HUD
    3. 当变量值变化时,更新得分和时间显示

    请注意,本篇教程涉及蓝图内容。如果你需要复习有关内容,请查看蓝图教程

    注意:本篇教程只是Unreal Engine 4系列教程的其中一篇:

    起步入门

    下载示例项目并解压。进入项目文件夹,双击BananaCollector.uproject打开项目。

    注意:如果你看到了项目是由较早的引擎版本创建的提示,这很正常(因为引擎经常更新版本)。你可以选择以拷贝副本的形式打开,也可以直接转换项目版本打开。

    点击Play开始游戏,控制白色方块接住掉落的图形。你可以通过移动鼠标平移方块。10秒后,图形会停止掉落。

    我们要做的第一件事就是创建HUD展示两个信息:

    • 玩家收集了多少个图形的计数
    • 距离图形停止掉落的倒计时

    其中需要使用到Widgets(控件)

    关于控件

    控件是一种提供简单功能的UI元素。比如,按钮控件提供了玩家可见可点击的物体。

    控件本身不一定是可视的。比如,网格面板挂件只是用于平均排布子元素。玩家看不见控件本身,但能看到控件的效果。

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

    你甚至可以创建一个铺满屏幕的控件。比如下面的控件作为一个标题界面铺满了屏幕。这个控件所包含了其他UI元素也都为控件。

    了解完什么是控件,现在动手创建一个。

    创建控件

    Content Browser界面进入UI文件夹。点击Add New按钮,选择创建User InterfaceWidget Blueprint,将其重名为WBP_HUD

    双击WBP_HUD打开UMG UI Designer。

    UMG UI Designer

    UMG UI Designer由七个主要元素组成:

    1. Designer:这个区域展示所选控件的外观。通过长按右键移动鼠标拖动面板,滑动滚轮缩放面板。
    2. Details:展示所选控件的参数
    3. Palette:可用控件列表
    4. Hierarchy:当前所使用的控件列表
    5. Animations:控件能够基于位置,大小等外观参数制作动画效果。该面板展示控件的所有动画
    6. Timeline:当你选中动画时,该面板会展示对应的动画参数和关键帧
    7. 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设成75Position 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轴上它有两个锚点。

    锚章代表了控件锚点所在位置,只要选中了控件,锚点标志就会展示在界面上。

    如图所示CounterTextCounterIcon的锚点已经在正确的位置上了,无须再做修改。

    接着,我们需要再创建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: 勾选
    • BrushImage: 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进行创建。

    让我们过一遍事件逻辑:

    1. 一旦Unreal生成BP_GameManagerRestartSetUpCamera函数就会执行。这些函数会设置一些变量和摄像机。如果你还不知道什么是函数,别担心。教程后面会有讲解。
      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 ManagerObject 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_GameManagerEvent BeginPlay部分逻辑,这里有两个函数:RestartSetUpCamera

    如果不用函数,那这部分的逻辑是这样的:

    可以看到,使用函数,整体逻辑看起来更简洁了。

    重用性

    使用函数的另一大原因是方便重用。比如,你想要重置计数和倒计时,通过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)节点。

    再来看下事件的顺序:

    1. 当外部调用UpdateCounterText,函数会从BP_GameManager引用获取ShapesCollected变量
    2. ToText (int)节点将ShapesCollected变量转换成Text类型
    3. 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引擎文档的控件类型参考页。

    如果你还想继续学习引擎其他内容,点击下篇教程,将教你如何整合已学知识,制作一个简单游戏!

  • 相关阅读:
    Leetcode645.Set Mismatch错误的集合
    Leetcode622.Design Circular Queue设计循环队列
    Leetcode628.Maximum Product of Three Numbers三个数的最大乘积
    Leetcode633.Sum of Square Numbers平方数之和
    Leetcode617.Merge Two Binary Trees合并二叉树
    Leetcode606.Construct String from Binary Tree根据二叉树创建字符串
    SQL Sever实验二 交互式 SQL
    [bzoj2124]等差子序列_线段树_hash
    [bzoj4084][Sdoi2015]双旋转字符串_hash
    [bzoj1708][Usaco2007 Oct]Money奶牛的硬币_动态规划_背包dp
  • 原文地址:https://www.cnblogs.com/leoin2012/p/11713476.html
Copyright © 2020-2023  润新知