Loading

UE4-初学UMG(一)

UMG(Unreal Motion Graphics UI Designer)

简单介绍

虚幻动态图形 UI 设计器是一款视觉 UI 创作工具,可用于创作想要呈现给用户的 UI 元素,比如游戏内的 HUD、菜单或与界面相关的其他图形。UMG 的核心是控件,即用于构成界面的一系列预先制作的功能(比如按钮、复选框、滑块、进度条等)。

我学习的是虚幻大学的First Hour With UMG课程,下载好相应资源后创建项目,得到以下几个文件夹,让我们依次看看它们的作用:

Character目录包含了所有人物类资源:Meshes(网格体)、Animations(动画)、Blueprints(蓝图)、Texture(图片资源文件)。

image-20210613112450816

Geometry包含了关卡中需要的各种mesh资源。

image-20210613152733130

Maps中目前只有我们当前正在使用的地图,之后还会包含我们的主菜单地图。

image-20210613152836977

Pickups中有各种事先准备好的对象,用于实现更多UMG交互操作。

image-20210613153004577

我们点进这个绿色的十字看看,发现它有一个打印字符串的节点,告诉我们已经恢复了一些生命值,我们之后将会用UMG界面去替代它。

image-20210613153215856

控件蓝图编辑器

UMG本质上是一种控件,它是一种可以在编辑器中创建的对象,允许我们在屏幕上显示各种内容,对于要显示的内容没有任何限制,你可以把它用于显示玩家的用户界面,用作显示生命值的平显界面(HUD),或者用于操作场景内对象的交互菜单。

创建控件的方式非常简单,只需要在内容浏览器中鼠标右击空白处,选择 User Interface -> Widget Blueprint 即可,但我们需要确保所有资源都摆放在合适的位置,保证项目结构的有序性,所以我们需要新建一个Widgets文件夹,在这个文件夹下新建一个控件蓝图,并改名为UMG_PlayerHUD,表示这是一个UMG控件,它将用来显示玩家的平显界面。

image-20210613154720494

双击图标就可以进入控件编辑器,这里借用一张网易游戏学院的图

img

这里可以稍微注意一下控件中的User Created

image-20210613204840848

它是一些用户预先创建好的控件,可以在其他的控件中复用。

我们可以在右上角看到,这是Designer部分,我们接着选择Graph

image-20210613210155539

它相当于传统的蓝图图表,包含一个基础的时间图表,还有函数、宏、变量、事件调度器以及可能出现的子图表。

控件蓝图剖析

介绍完控件编辑器之后,我们应该对编辑器的布局有了大致了解,现在来具体了解下控件本身。

首先让我们看看Image控件,这个控件允许我们显示颜色(Color)、纹理(Texture)或类似效果,我们可以把它从控制板(Palette)中直接拖入视口(ViewPort),或者直接把它拖到另一个控件上面,让它变成子节点。我们现在把它拖入视口中,现在就拥有了一张图片,可以四处移动它,可以看到右上角的位置信息会实时更新,如果调整它的尺寸,尺寸信息就会更新,非常简单。有一点非常重要,那就是要了解控件和UMG系统采用的层级方式,它们有一个固定的父子关系:

image-20210614105741570

这是Canvas Panel,它是父节点,可以在右边的细节面板看到他有Behavior、Accessibility、Render Transform这些通用属性(Common Properties)

image-20210614110021783

这是Image,它是Canvas Panel的子节点,它同样具备这些通用属性,而上方是这张图片的专有属性,比如Appearance,其中包括Brush,图片显示的内容以及它的颜色和不透明度(Color and Opacity),在它的上方,只要控件是子节点,比如Image是Canvas Panel的子节点,它就有一个Slot(Canvas Panel Slot),Slot会因为子节点所在面板而有所不同,这里子节点位于Canvas Panel下,我们可以随意移动Image和对它进行缩放,在面板中可以看到数据的实时变化,还有其他一些设置,例如Anchors(锚点),Alignment(对齐),但这些都是跟Canvas Panel相关的设置,如果我们将父节点改为其他节点,则对应Slot的属性会有不同,这里我们选择Vertical Box作为Image的父节点,可以看到Slot变得不一样了

image-20210614111144001

它的Slot变成了Vertical Box Slot,因为父节点是Vertical Box,它的属性不一样了,尺寸和位置属性消失了,只剩下一些基本的布局设置,为什么会这样呢?我们将鼠标悬浮在Vertical Box上方

image-20210613110643061

可以看到Vertical Box的基本作用是允许子对象自动按照垂直布局排列,可以把它想象成一张列表,它没有位置和尺寸信息,子对象会根据父对象的尺寸进行调整,任何新添加的子控件,都会自动排列到下方,它们的尺寸都是由父节点以及插槽设置决定的,我们只能改变Slot中的设置,使它们左对齐居中右对齐(水平布局)等等。

image-20210614112056026

如果你试图把某个控件放在一个特定位置,比如放在屏幕左上角距离边缘20像素的位置,你就不能把它放在某个不支持这么操作的Panel中,必须使一个支持固定布局的面板,比如Canvas Panel。每个面板都有一些特定的设置和选项供它们的子节点使用,这些在文档中都有详细说明,你可以进一步查阅了解。

控件的布局

我们创建的第一个UI将用于帮助玩家在游戏中实时查看游戏数据。在创建过程中,我们将介绍HUD系统和UMG系统的区别,以及两者各自的优点。

介绍完UMG编辑器的基础概念后,让我们来看一下项目,运行项目,以便确定用户界面中需要哪些控件,当前还没有任何控件,但是屏幕中间有一个准星,当我们开枪时,左上角会显示弹药数量,如果我们捡取医疗包,生命值就会上升或下降,但现在我们看不到这些数值,因为没有UI能持续显示这些数值,我们需要添加生命值和弹药UI,并且弄清楚,为什么准星位于屏幕中间,并解决这个问题。

image-20210614122236528

让我们先来看看准星,在UMG系统被创建之前,HUD类就已经创建好了,我们依次打开Character -> Blueprints,可以找到名为HUD_FirstHourUMG的文件image-20210614124907215

如果把它打开,就能看到准星的来源image-20210614125004502

HUD类会作为游戏框架的一部分进行绘制,所以它每一张都会在屏幕中心绘制准星纹理,我们不应该同时使用HUD和UMG系统,所以要把准星的绘制逻辑从HUD中转移到UMG中,但首先我们要让HUD停止绘制准星,打开游戏模式(GameMode),也就是GM_FirstHourUMG

image-20210614125200824

image-20210614125303316

将其中的HUD Class从HUD_FirstHourUMG改为None或HUD,无论哪个都行,这两个类都不会绘制准星,将它关闭,然后播放游戏

image-20210614130050937

可以看到准星消失了,第一个问题就这么解决了,接下来是用UMG控件显示准星

回到我们创建的UMG_PlayerHUD,添加一个准星,在控制板中选中Image,把它拖到屏幕中间,在细节面板的Appearance中找到Brush,展开它

image-20210614160333581

选择准星的图片

image-20210614160358215

可以看到图片的尺寸是16*16,但是注意,图片的父对象是画布面板(Canvas Panel),所以面板实际上决定了图片大小,我们可以选择size to content,图片就会自动调整到默认的尺寸

image-20210614163925723

我们发现准星看起来有点小,我们把大小调整成48*48

image-20210614163954374

看起来好多了,再通过目测大概调整一下它的位置。

接下来添加文本控件,用来显示生命值和弹药数量,分别在左下角和右下角拖入两个文本控件

image-20210614164249815

现在就能显示生命值和弹药了,我们调整一下文本,让它看起来更漂亮些,在左下角的文本控件的Content输入Health: 100

image-20210614164448910

然后在另一个文本控件中输入Ammo: 100,现在屏幕上就会显示生命值和弹药数量

image-20210614164604194

我们可以稍微调整一下文本框的位置,让它们对齐左下角和右下角,注意一下控件周围的绿色方框,绿色方框实际上表示控件的具体大小,文本现在超出了方框

image-20210614164913706

我们同样勾选Size to content,方框会自动调整大小

image-20210614165052036

我们又发现字体有点小,在Appearance -> font中,可以找到size,将大小调整为36

image-20210614165223913

image-20210614165305354

这时我们发现它的一部分内容超出了方框,这条边框表示视口的大小,决定了当前设置下,哪些内容会出现在屏幕上,如果我们运行游戏,我们就会发现,这些字符全部位于屏幕外面,所以我们需要再调整一下它的位置,让它位于边框内部。

image-20210614170530233

现在基本上就有了我们想要的效果,中间是准星,底部是生命值和弹药,看起来不错,屏幕中已经有了我们想要的UI,但是UI的数值并不会发生变动,所以接着我们要设置UI事件,以便将人物数值发送给屏幕上的UI

控件的核心事件

这节课介绍的事件系统有助于在游戏数据发生变动时实时更新UI界面。我们将介绍一些引擎内置的、对于控件极为重要的事件。

设置完玩家的HUD界面后,我们接着要让UI与数据或者说代码挂钩,我们可以通过蓝图事件图表实现这点,再次进入Graph,当中有一些默认创建好的事件

image-20210614171258708

此外我们还能自己创建事件(Event),用来执行自定义操作。

我们现在有Construct事件,在构造或创建控件时,会触发这个事件,我们的项目中不会用到它,所以把它删掉,选中它按Delete即可。

然后是Event Pre Construct,它与Construct事件类似,只不过它是在编辑器中生效,例如,如果我们现在想修改文本,我们可以使用Pre Construct事件,可以用它在编辑器中修改文本,我们不必运行游戏来查看更改效果,这个事件有助于你在设计一些嵌套控件时,或使用一些高级特性时实时更新内容,我们在项目中同样不会用到它。

最后是Event Tick,它和普通的Tick事件一样,基本上游戏每次刷新逻辑时,或者说游戏中的每一帧都会调用Tick事件,通常你不应该使用这个事件,因为它的开销非常大,每一帧都会执行,假设说,你把玩家的生命值更新逻辑,放在Tick事件中执行,假设玩家的生命值每隔几秒才变化一次,因为它们不会被频繁击中,所以每帧都更新生命值就会非常浪费。如果在计时器这类功能,就需要每帧都更新,例如赛车游戏中的那些非常精准的计时器,它们的更新频率可能只有千分之一秒,这时就要用到Tick事件,在我们的项目中也不会用到Tick,所以把它也删掉。

我们要做的是创建一个自定义事件,我们会利用数据驱动的方式来更新我们的界面,如果玩家生命值和弹药量发生变化,我们就更新界面,不需要每一帧都检查弹药情况,只有当玩家拾取弹药时,我们才会更新它,要尽可能简单。

右键点击空白处,创建一个自定义事件,搜索Custom Eventimage-20210614181309308

起一个简单的名称

image-20210614181455963

每当我们需要更新生命值时,我们就调用这个事件,然后设置一个新的生命值,我们的UI会尽可能简单,不会有花里胡哨的布局和复合型控件,只会用到一些非常简单的文本,比如"生命值:XX"以及”弹药:XX“,我们需要获取一个数值,以便更新UI,为此,要为我们的自定义事件添加一个参数,在左侧的细节面板底部,我们可以添加一个参数

image-20210614181927149

参数名称可以任意设置,这里我将它命名为NewValue,参数类型也可以任意选择,这里我们用一个Float类型的数来表示生命值,因为我们要对生命值稍加改动,然后再显示它,这样一来之后在显示玩家UI时就有更多的选择余地,例如,我们传入一个生命值,比如70,可以把它与一个进度条挂钩,用来充当玩家的血条,之后就能有更多的选择余地。

为了更新文本,我们需要设置数值,回到Designer,找到Text

image-20210614183001164

Content就是我们需要更新的内容,但在Graph中,我们没办法获取这个文本,我们需要把它保存为变量

image-20210614183158690

这里可以看到变量Image,但没有发现Text,原因是默认情况下,文本不会自动保存为变量,如果查看右上角的细节面板,我们可以找到 is variable 选项,勾选它,点击编译,然后再回到Graph中,我们发现Text出现在了变量中。

image-20210614183423582

image-20210614183442381

我们分别对文本变量进行重命名,编译,现在就有两个变量可供使用了。

image-20210614183710858

两者都是引用类型的数据,可以用来访问生命值和弹药的数量,我们需要更改文本的属性,可以在Graph中直接将其拖入视口,选择get

image-20210614183953975

或者直接按住 ctrl 将其拖出,这样我们就得到了这个变量,从它的引脚拉出引线,搜索set text

image-20210614184109203

可以看到widget下的setText可以直接设置文本,我们选择它

image-20210614184240874

在 In Text 里输入的任何内容都会作为文本显示在屏幕上。

把UpdateHealth的执行引脚与其相连

image-20210614184352366

如果就这样显示画面,生命值文本会是空的,我们需要把New Value与In Text相连,它会自动创建一个转换节点,能将任何输入都转换成字符串并传入右边

image-20210614184607316

但问题是,左边是个数值100,而右边是文本,而我们需要显示”生命值:100“,所以需要添加一些辅助节点,我们可以使用Append nodes

搜索Append,可以找到 String -> Append

image-20210614184927446

它能将多个字符串合并成一个字符串,我们将A处的文本改为Health: ,并把New Value与B相连,再把返回值与In Text相连

image-20210614185217387

它的作用就是先输出Health: ,然后输出B处传入的数值

我们将以上节点复制,修改一些参数,创建一个类似的UpdateAmmo事件

image-20210614185652833

现在我们已经设置好了前端界面(Designer),可以在屏幕上显示内容,我们还设置好了后端逻辑(Graph),每当我们调用UpdateHealth和UpdateAmmo时,前端界面就会发生变化,一切就绪。当然,屏幕上还没有任何东西,数值也没有关联,但我们的用户界面已经为下一步做好了准备,也就是在屏幕上显示HUD。

posted @ 2021-08-13 17:32  泠枫Jun  阅读(1636)  评论(0编辑  收藏  举报