书名:精通Unreal游戏引擎
ISBN:978-7-115-40646-0
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
• 著 [英] Ryan Shah
译 王晓慧
责任编辑 陈冀康
• 人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
• 读者服务热线:(010)81055410
反盗版热线:(010)81055315
作者简介
Ryan Shah是Kitatus Studios的项目主管和首席程序员,有超过10年的电子游戏开发经验,开发过各种类型的电子游戏。
在创办Kitatus Studios之前,Ryan是一位自由撰稿人,曾出版小说。基于曾经当过作家的经历,Ryan又转向电子游戏开发,以实现自己的想法作为毕生理想。
Ryan的个人主页是http://kitatusstudios.co.uk,邮箱是contact@kitatusstudios.co.uk。
译者简介
王晓慧,女,1987年5月6日生。2014年7月于清华大学计算机科学与技术专业获工学博士学位,2014年9月至今于北京科技大学机械工程学院工业设计系担任讲师。计算机学会会员,信息与交互设计专委会高级会员。主要研究方向为计算机科学与设计学交叉、虚拟现实、大数据与信息可视化、情感计算、人机交互等。在国内外学术期刊和会议上发表论文16篇,其中被SCI收录3篇,被EI收录10篇。邮箱是xiaohui0506@gmail.com。
作者致谢
非常感谢我漂亮的女朋友Scarlett,她在任何时候都相信我,她的耐心一直鼓舞着我。 感谢Epic基于Unreal Engine 4创建了这么丰富并且容易上手的系统。Epic无愧于被人们称为游戏的改造者!
还要感谢你们——我的读者。可能我不知道你们是谁,但是通过购买这本书,你们不仅支持了我,而且支持了电子游戏产业。有可能这本书帮助您做出了世界上最好的游戏,谁知道呢?一切皆有可能!
本书特色
Unreal Engine是目前世界知名度很高、应用广泛的顶尖游戏引擎之一,最新版本的Unreal Engine 4所推出的编辑器Blueprints非常强大且灵活,为设计人员提供了一款高效的设计工具。本书图文并茂地为读者介绍了诸多示例及方法,作者将自己数年的积累整理成39个步骤,帮助读者快速学习该工具。
Simplified Chinese translation copyright ©2015 by Posts and Telecommunications Press
ALL RIGHTS RESERVED
Master the Art of Unreal Engine 4 Blueprints
Copyright © 2014 by Ryan Shah
本书中文简体版由Ryan Shah授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。
版权所有,侵权必究。
Unreal Engine是目前世界知名度高、应用广泛的游戏引擎之一,最新版本的Unreal Engine 4所推出的编辑器Blueprints是使用基于节点的交互界面来创建游戏元素和关卡。该系统非常强大且灵活,为设计人员提供了一款高效的设计工具。
本书作者有超过10年的游戏设计开发经验,他用具体案例深入浅出地介绍了Unreal Engine 4 Blueprints。本书通过39个步骤引导读者掌握开发技巧,从项目创建开始,学会使用蓝图并操纵蓝图中的摄像机,然后创建自己的控件、灯光以及导航网络等,同时配合以项目间的资源调动,最终完成了点击式冒险游戏的开发。
本书以简洁、有趣的方式讲解Unreal Engine 4 Blueprints,适合所有想开发电子游戏的读者,以及想要学习Unreal Engine 4游戏引擎的读者参考阅读。
Unreal Engine 4是当下比较流行的电子游戏开发环境Unreal Engine的最新版本。Unreal Engine是第一代游戏机诞生以来各类游戏的动力源泉,无论个人还是商业开发者,都可以使用Unreal Engine来开发他们理想的项目。在最新的Unreal Engine 4中,Epic极大地提升了引擎的品质,将未来的效果变成了现实。无论项目大小,无论是商业项目还是个人项目,现在都是使用Unreal Engine 4实现的最好时机。
本书采用简洁、清晰、富含信息量并且有趣的方式来开发Unreal Engine 4项目,不需要编写代码。通过阅读本书,您可以完整地创建各种小型蓝图项目,掌握开发电子游戏的基本知识。在掌握Unreal Engine 4蓝图系统的基础上,您还会了解到引擎背后的秘密。
为了更好地使用这本书,您需要一台能够运行Unreal Engine 4的Windows、Mac或者Linux系统的计算机。该计算机至少需要具备以下配置:
此外,还需要Unreal Engine(版本4.4或以上)。
本书面向任何想开发电子游戏,但又不知道如何开始的读者;面向希望借助Unreal Engine 4的力量来将自己的创作推向更高层次的读者;面向希望不写一行代码就可以开发电子游戏的读者。
对于熟悉Unreal Engine 4的读者来说,阅读本书比较容易,本书中每个知识点都讲解得比较清楚,并且配有操作过程的截图,让Unreal Engine 4的蓝图系统掌握起来轻而易举。对于没有游戏开发经验的读者来说,阅读本书也应该没有问题。如果您需要额外的帮助,可以直接在Unreal Engine论坛(http://forums.unrealengine.com)上提问,或者发邮件到contact@kitatusstudios.co.uk。
我希望收到反馈。无论是表扬还是批评,都欢迎读者反馈给我。无论读者是喜欢还是讨厌这本书,我都希望知道。反馈对我很重要,它可以帮助我纠正发现的错误,让我知道这本书写的质量如何。我是一个完美主义者,会竭尽全力做到最好。所以本书有任何可以改进的地方,随时给我发邮件到contact@kitatusstudios.co.uk。
如果您购买本书,还可以获得更多的内容,如本书的彩色插图和项目文件。到http://content.Kitatusstudios.co.ukto下载这些文件即可!
我在撰写本书时,已经确定没有错误。但是随着引擎的更新,可能会有些变化。如果万一有些代码不能运行了,请及时联系我:contact@kitatusstudios.co.uk。这不仅能保证本书的完整性,而且可以避免其他人遇到同样的错误,保证本书顺畅的阅读体验。凡是指出错误的读者,他们的姓名都会记载在下一个版本中!
读者可以从http://content.kitatusstudios.co.uk下载本书中的彩色插图和Unreal Engine 4的项目文件。
如果您有任何问题,可以发邮件到contact@kitatusstudios.co.uk。这个邮箱是开放的,欢迎随时联系我们。
我们的任务是什么
在本书中,我们将要开发一个点击式冒险游戏。因为我想充分使用Unreal Engine 4的强大功能,所以将开发一个3D点击式冒险游戏。它类似于Telltale Games开发的游戏,如Sam and Max(妙探闯通关)、Tales Of Monkey Island(猴岛故事)、Back To The Future(回到未来)等。
下面我们将要开发什么呢?
让我们开始任务
Third-Person Blueprint(第三人物视角)
2~4小时
一个交互式的场景,玩家可以在场景中走动、与其他对象交互、拿物体等。我们也会通过玩家的对话和简单的菜单实现Matinee场景(Cutscenes),过场动画及玩家主导的游戏体验。
完成任务之后,您将能够:
亲爱的开发者们,大家好!今天我们来解决Bojan邮件中提到的问题:
“我想做一个点击式冒险游戏,以及一些智力逻辑类游戏。可以在您以后的书中讲解一下吗?”
Bojan,下面我们就解决这些问题!从最基础的知识入手,循序渐进地制作自己的3D 点击式冒险游戏。
开始Unreal之旅的第一步是下载安装并创建一个新的工程。已有基础的读者对下面的步骤可谓轻车熟路了,而对于第一次接触Unreal Engine的读者来说,下面简单的讲解可以帮助您快速上手。
首先,我们需要打开Unreal Engine启动程序,安装完Unreal Engine4[1],您就可以在桌面上找到它的快捷方式,如图1所示。
图1 Unreal Engine4启动程序的快捷方式
双击该图标,打开Unreal Engine4启动程序,显示欢迎界面,如图2所示(注意:随着Unreal Engine版本的更新,该界面会有所不同,但熟悉了一个版本之后会很容易上手)。
图2 Unreal Engine4启动程序的欢迎界面
注意:
如果图片不够清晰,可以从http://content.kitatusstudios.co.uk免费下载其高清版本。
在我们的游戏项目中,当前选中的玩家通常需要使用高亮材质显示,但我们不必亲自绘制这些材质,Unreal Engine已经为我们准备好了,下面讲解如何使用。首先进入启动程序中的Learn(学习)选项卡,单击Content Examples(内容示例)打开下载页。选择您想要安装的Unreal Engine版本,单击Download(下载)免费下载由Epic Games提供的项目文件,帮助您掌握Unreal Engine。安装成功之后,Download(下载)按钮会变成Create Project(新建项目)按钮,单击进入并输入项目名称就可以新建项目。
除了Learn(学习)选项卡之外,您还可以在Library(库)选项卡下面找到Content Examples(内容示例)页面。打开Library选项卡,您可以看到所有已经建立好的项目,如图3所示。向下滑动到Vault(储藏室)部分,可以找到已经下载好的Content Examples(内容示例),单击它,输入项目名称,就可以创建新的项目[2]。
图3 Library(库)选项窗口
注意:
图中“Secrets!”部分隐藏了作者当前的项目,您的Unreal Engine中不会出现这部分内容。
现在Content Examples(内容示例)已经下载创建成功,我们不是直接打开它,而是新建项目,然后将其中的高亮材质导入到项目中(正如当一个人不存在时,不能给他分发点心一样)。
在启动程序的左上角有一个很漂亮的Launch(加载)按钮,单击它或者在Library(库)选项窗口中选择一个Unreal Engine版本,单击版本号下方的Launch(加载)按钮(注意选择版本号4.5或以上)。Unreal Engine启动后,您将看到如图4所示的窗口。
图4 Unreal项目浏览器窗口
如图4所示是Unreal Engine的项目浏览器窗口,您可以随意地新建项目,或加载项目文件夹中已有的项目。对于我们的点击式冒险游戏,需要新建一个Blueprint project(蓝图项目),单击上方的New Project(新建项目)可进入新建项目窗口,如图5所示。
图5 New Project(新建项目)窗口
新建项目窗口的各项功能一目了然,Projects(项目)和 New Project (新建项目)两个按钮下面有两个选项卡Blueprint(蓝图)和C++,让您选择作为新建项目起点来使用的模板类型。
从技术上来讲,在Unreal Engine4中使用哪个模板区别不大,因为您可以随时添加Blueprint(蓝图)或C++代码到任何项目中。但为了讲解方便,本书将使用蓝图进行描述,所以读者务必使用Blueprint选项卡。
在Blueprint(蓝图)和C++选项卡内有一些模板供选择。因为我们要创建一个Telltale风格[3]的点击交互游戏,需要使用鼠标或游戏控制器来进行移动,所以单击选择Third Person(第三人物视角)模板,在Unreal Engine4.5中,它的样子如图6所示。
选择了Third Person模板之后,需要在模板视图的下方选择项目的设置。一般来说,可以根据您的需要来选择设置,本书所选择的设置如图7所示。我们选择项目的目标硬件类型是桌面或游戏机,具有最高质量的画质级别,以便可以利用Unreal Engine4 的所有高级渲染功能。最后我们选择Starter Content(初学者内容),它包含一些材质和简单物体,免去了我们亲自制备这些素材的麻烦。
图6 Third Person(第三人物视角)模板
图7 项目设置
注意:
图中3个标题分别是Desktop/Console(桌面/控制台)-Maximum Quality(最高画质)- With Starter Content (包含初学者内容)。
最后,在窗口的最下面,设置项目的存储位置和名称。如果默认位置不合适,您可以随意设置新的路径和名称。这里将项目命名为ArtofBP_03。
图8 设置项目的存储位置和名称
所有参数设置完毕后,单击Create Project(创建项目),Unreal Engine4会开始创建项目,首次创建需要一到两分钟。项目创建加载完毕,就可以看到主窗口了,如图9所示。
图9 项目主窗口
注意:
现在可以根据您的想法随意编辑项目内容了!但是由于屏幕分辨率不同,看到的界面可能略有不同。
最后,选择主菜单中的File > Save All(文件>保存所有)命令,保存项目,并关闭项目窗口。
现在我们的项目已经创建好了,下一节将介绍如何把Content Example(内容示例)中的Highlight material(高亮材质)导入到我们的项目中。
[1] Unreal Engine 4指的是4.x系列——译者注。
[2] 根据译者的Unreal使用经验,Vault部分存放的是所有已经下载的项目模板,原文中的install指的是根据模板创建新的项目——译者注。
[3] Telltale Games是一个有名的电脑游戏设计团队,以卢卡斯冒险游戏著称——译者注。
只要项目已经保存,您就可以在Unreal Engine启动程序中找到并打开它。这一次,我们不是新建项目,而是打开已经创建的Content Examples(内容示例)项目(如果没有下载安装Content Examples,请参考第1步)。
打开Content Examples(内容示例)项目,使用默认位于窗口左下方的Content Browser(内容浏览器),如图10所示,找到“Game/ExampleContent/Blueprint_Communications/ Materials”文件夹(双击文件夹展开其子目录)。
图10 Content Browser(内容浏览器)窗口
在该文件夹中找到名为M_Highlight的材质,可以通过Search Materials(搜索材质)搜索框来查找。鼠标右键(Mac上是Ctrl键+鼠标左键)单击材质M_Highlight,在弹出的菜单中选择 Asset Actions(资源操作),并在弹出的二级菜单中单击Migrate(迁移),如图11所示。
图11 材质操作窗口
此时会弹出Asset Report(资源报告)窗口(如图12所示),该窗口将显示哪些资源会被导出然后再导入到我们选择的最新项目。我们要移动的资源是材质M_Highlight,资源报告(如图12所示)显示正确,单击OK(确定)按钮进入下一个窗口,我们将在这个窗口中选择迁移的目标工程。
图12 资源报告窗口
接着,弹出Browse for Folder(浏览文件夹)窗口,如图13所示。定位到上一节所创建的点击式项目,找到该项目文件夹下的Content文件夹,正如在Content Browser(内容浏览器)中所看到的一样,将M_Highlight迁移到该文件夹下。
Unreal Engine4默认的项目创建路径是“C:\Users\YOURUSERNAMEHERE\ Documents\Unreal Projects”(例如,作者的Unreal Engine项目路径是“C:\Users\ Ryuuzaki\Documents\Unreal Projects”)。当然,如果您修改了创建路径,它也会记住这一路径并将其设置为默认。
图13 浏览文件夹窗口
定位到上一节所创建的点击式项目ArtofBP_03,找到该项目文件夹下的Content(内容)文件夹,如图14所示。最后,单击OK(确定)按钮,Unreal Engine将复制材质M_Highlight到该目录下。
图14 浏览文件夹窗口
我们为什么这样做,而不采用手动导出资源再到另一个项目中手动导入的方式,或者是直接在项目之间手动拖拽的方式呢?您可能认为是为了操作便捷,但是实际原因是兼容性问题。因为在4.5版本的Unreal Engine中,虽然支持手工拖拽及资源导出导入,但这一过程会丢失资源的关联信息,例如纹理和材质之间的关联信息等,导致在新的项目中资源不可用。
毋庸置疑,Unreal Engine之后的版本将解决这一问题,但是目前还是建议使用migrating(迁移)功能。
现在,材质M_Highlight已经在我们的项目中了。关闭Content Examples(内容示例)项目,重新打开我们的点击式游戏项目。这时,在Content Browser(内容浏览器)中多了一个名为Example Content的文件夹(如图15所示)。进入该文件夹,您会在这里找到M_Highlight材质,文件夹结构与Content Examples(内容示例)中一样。
图15 Content Browser(内容浏览器)窗口
目前对材质M_Highlight的迁移介绍先告一段落,之后会继续讨论。下面将继续我们的点击式游戏项目。
现在我们的项目中已经有了高亮材质,在使用它之前,我们需要一张地图。更具体地来说,需要一块游戏场地来展示我们的点击式游戏,这里不适合使用大的开放式环境。您不要误解,一些点击式游戏需要这种场地,但是这里为了展示“点击式技巧”,一个小场地即可。
读者可以按照下面一些纲要性的介绍来制作地图,或者直接从[http://content. kitatusstudios.co.uk](http://content. kitatusstudios.co.uk)下载。诸如“在这里创建这个,在那里创建那个”的介绍看上去很难掌握,但是别担心,我们仅仅在现有的样例地图Example_Map上做最少的改动,让它更适合我们的点击式冒险游戏。
在继续之前,我们先学习一下如何在场景中删除对象。非常简单!首先,也是最重要的,是要确定屏幕上显示的是项目主窗口,即Content Browser(内容浏览器)在窗口的左下角,场景视图在中间,如图16所示。
图16 项目主窗口
我们继续关注场景视图。单击选中楼梯,单击键盘上的Delete键,或者右键(Mac上是Ctrl键+鼠标左键)单击楼梯,在弹出的菜单中选择Edit(编辑)>Delete(删除),楼梯消失,如图17所示。
图17 删除楼梯后的项目场景视图
重复上述操作,删除与楼梯连接的除了墙和地板以外的所有几何体(同时删除文本Third Person Template)。这时您将看到类似储藏间的地图,如图18所示。
图18 地图
这就是我们的空白场地。下面我们将要创建一个简单的地图来展示我们的点击式冒险游戏。
首先,前往Modes(模式)窗口(通常在项目主窗口的左上角),如图19所示。
图19 Modes(模式)窗口
注意:
该工具栏会根据您屏幕的分辨率隐藏一些选项。拖拉工具栏的底部和侧面边框扩展它,就可以看到所有选项!
下面使用BSP刷子创建一些几何体。在此之前,让我来解释一下什么是BSP,使用BSP的好处和注意事项。
BSP是可编辑的几何体,可以用来充实项目的场景。想一下,您在使用可定制的乐高玩具创建关卡时,可以很快得到雏形,但是乐高玩具并不适用于制作最终产品。为什么呢?因为BSP非常占用资源。BSP的主要功能是帮助您勾勒出一个关卡的轮廓,和正常的静态网格相比,它们在渲染的时候会消耗更多的内存和资源。
读到这里,您肯定要问“为什么一开始还要使用BSP呢?”因为BSP可以在Unreal Engine 4中快速简单地创建一个游戏关卡。在30秒之内,您就能创建一个可以自由行动的房间。
此外,您可以将任意的BSP(或者一些BSP的集合)转换为一个静态网格,然后将这个静态网格导出到您喜欢的3D建模程序中,进而以它们为基础创建最终的游戏关卡。一旦创建完毕,还能将该网格导回Engine来代替BSP,给您节省了大量的时间和不必要的努力。
关于BSP的更多信息,推荐您到Unreal Engine网站上或者在Unreal Engine 4的窗口中单击F1查看相关文档。
现在我们在场景中创建两面墙,把大块空间分割成几个小块,让我们的地图显得更有深度,也更有趣。
前往Mode(模式)工具箱(记得调整窗口大小以看到所有选项),选择类别BSP,如图20所示,单击Box(盒子)并拖拽它到项目场景视图中。
图20 Modes(模式)工具箱中BSP的Box(盒子)选项
现在场景中在您放置BSP的地方已经有了一个大小合适的盒子。需要注意的是,如果您的盒子有一半陷在了地板里,或者有一半嵌入了墙中,可以使用Transform(平移)工具(由3个箭头组成,分别是蓝色、红色和绿色)移动盒子让它刚好坐落在地面上。如果您没有看到平移工具,在场景中直接单击盒子即可,如图21所示。
图21 BSP的Box(盒子)实例
注意:
为了让您看清图像中的盒子,这里对地面添加了材质。如果书中图像的分辨率不高,可以从http://content.kitatusstudios.co.uk网站上下载本书中所有图像的高清版本。
这个盒子看起来不错,但是我们需要的是在当前场景中建一面墙。类似前面的操作,可以很容易地把盒子变成一面墙(记住:直接单击盒子,平移工具就出现了),先把盒子移动到地图中间,如图22所示。
图22 场景视图
注意:
当移动盒子的时候,您可能不经意地把它放在了场景中某个物体的上面,这个物体看起来像一个操控杆或者一面旗,且会从中出来一个蓝色的箭头。其中,这个操控杆是玩家的初始位置, 箭头是玩家面朝的方向。如果操纵杆在盒子内部,情况会很糟糕,因为玩家将出现在盒子内部,所以在移动盒子的时候请注意这一点。
您可以单击它,使用平移工具将操纵杆移出去,或者在Scene Outliner(场景大纲视图,通常在工作区的右上方)中找到Player Start,单击Player Start并用平移工具将其移出去。
现在,盒子已经在地图中间了,但是它看起来并不像一面墙。再次前往Modes(模式)工具箱(我们创建盒子的地方),您会发现Modes(模式)窗口的上方有5个按钮,如图23所示。
图23 Modes(模式)窗口上方的5个按钮
我们要把立方体变成一面墙,所以使用第五个工具—Geometry Edit(几何体编辑)。直接单击该工具按钮,Modes(模式)工具箱内的选项会发生变化。该工具会自动加载默认设置—Edit(编辑)模式,如图24所示。在这5个按钮下方有一些单选框,直接单击来实现模式的切换。
这里我们需要Edit(编辑)模式,所以不改变任何设置,但是有必要了解这些模式选项,方便以后使用。
图24 Geometry Edit(几何体编辑)工具
小提示:
直接单击Geometry Edit(几何体编辑)按钮来激活该工具。Unreal Engine 4的大部分工具,会有一个明显的激活提示,通常工具按钮会变成橘黄色。Modes(模式)工具栏有一点不同,这里为什么要介绍这个呢?因为很多时候,当您想把一个BSP从位置A移动到位置B时,有可能不经意的选中了盒子的一面然后把盒子变大了。如何阻止这种情况发生呢?很简单!时不时地查看Modes(模式)窗口,以确定当前选中的是Place(放置)工具,而不是其他工具。
现在已经选中了Geometry Edit(几何体编辑)工具,下面单击选中场景视图中待编辑的BSP。因为我们想编辑之前创建的盒子,所以单击盒子。这时盒子的边缘被黄色和蓝色高亮显示(盒子的顶角上出现蓝色方块),如图25所示,表示盒子已经被选中,就可以进行编辑了。
图25 处于选中状态的盒子
注意:
单击盒子,Gizmo(小工具,选中对象中央的红绿蓝箭头组合)变成了椭圆形状?还是箭头变成了立方体?一旦出现了这两种情况,表示当前处于错误的Gizmo mode(编辑模式)。我们可以在Gizmo Selector(编辑模式选择器)中选择正确的编辑模式。Gizmo Selector(编辑模式选择器)在主场景视图中,位于屏幕的中间或者是右上方(这取决于您屏幕的大小),如图26所示。
图26 Gizmo Selector(编辑模式选择器)
黄色底的选项表示当前选中的编辑模式。一共有3个选项:左边的表示Transform(平移),可以在XYZ平面上移动对象;中间的表示Rotator(旋转),可以沿着XYZ坐标旋转对象;右边的表示Scale(缩放),可以使对象变大或者变小。
为了借助Geometry Edit(几何体编辑)工具将盒子变成一面墙的形状,我们使用最左边的Transform(平移)模式。如果该模式当前没有被选中,直接单击Gizmo Selector(编辑模式选择器)左边的按钮将编辑模式切换为Transform(平移)。
现在我们可以编辑盒子的大小了,但是如何精确地控制呢?一旦盒子被选中,可以选择盒子的一个面来编辑。所以首先要确定盒子处于选中状态,然后单击任意一面。正处于编辑状态的面会被黄色高亮显示,您可以准确定位它,如图27所示。
图27 黄色高亮显示盒子中处于编辑状态的面
对于这个面,我们需要把墙变得窄一点。虽然厚墙也可以,但是窄墙看起来更加美观!在Transform(平移)编辑模式下,单击绿箭头,按住鼠标左键拖拽箭头直到盒子的厚度是原来的一半,如图28所示。
图28 变窄的盒子
下面就使用上述方法创建一面墙。选中您刚刚编辑的那个面左边的面,拖拽其直至与外墙(首次创建项目时自动生成的)重合,如图29所示。
图29 处于编辑状态的盒子
墙的一侧已经编辑完毕,单击这面墙的另一侧,拖拽其直至与另一面外墙重合,这时游戏场地被分割成了两部分,如图30所示。
图30 处于编辑状态的墙
如何让墙变得高一点?选中最上面的面,拖拽其与外墙的高度一致即可,如图31所示。
图31 由盒子编辑而来的墙
我们已经有了一面墙,把场景分割成了两部分。但是在完成之前,还有一些操作。退出Geometry Edit(几何体编辑)工具,前往Modes(模式)窗口,单击Place(放置)按钮(Modes窗口的最上面,其图标是一个立方体,前面放着一个灯泡),如图32所示。
图32 模式工具栏Place(放置)工具
然后单击选中刚刚创建好的墙,如图33所示。
图33 墙的选中状态
同时按Ctrl+C组合键复制这面墙,然后同时按Ctrl+V组合键粘贴得到墙的一个副本。也可以右键单击这面墙(Mac上是Ctrl键+鼠标左键),在下拉菜单中选择Edit(编辑),在弹出的二级菜单中选择Duplicate(复制)。
此时您可能看不到复制得到的墙。到场景视图的中间或者中间偏右的位置找到Gizmo Selector(编辑模式选择器),选择中间的Rotator(旋转)模式。将这面墙向左或向右(使用出现的标示符中的蓝色区域)旋转90°,这时在地图中间出现了一个大大的X或+号,如图34所示。
图34 旋转之后的墙
如何使得新建的墙与外墙恰好吻合呢?使用之前学过的方法调整墙的长度,即使用Geometry Edit(几何体编辑)工具进行缩放得到合适的尺寸。
图35 调整尺寸之后的墙
现在场景中已经有4个完美分割好的房间让我们来创建一个很酷的项目。但是您有没有注意到哪里有些不对劲,好像忽略了很重要的东西?
由于这两面墙的缘故,这些房间之间不能穿梭。如何解决这一问题呢?下面我们将学习Subtraction Volume(减法体)。
什么是Subtraction Volume(减法体)?Subtraction Volume(减法体)和BSP网格配合使用,可以从场景中删除BSP块。例如使用BSP创建一面墙,墙中有一扇门。首先新建一面墙,然后使用减法BSP从墙中凿出一扇门。下面我们就来学习如何实现。
创建减法BSP的过程和上一节我们创建墙的过程没有太大区别。事实上,这两个过程几乎一样。首先创建另一个立方体。如同前面的操作,前往Modes(模式)窗口(通常在项目主窗口的左上角),如图36所示。
图36 Modes(模式)工具箱
注意:
该工具栏会根据您屏幕的分辨率隐藏一些选项。拖拉工具栏的底部和侧面边框来扩展它,就可以看到所有选项!
选择BSP,如图37所示,单击Box(盒子)并拖拽它到项目场景视图中。
图37 Modes(模式)窗口中BSP的Box(盒子)选项
现在场景中在您放置BSP的地方已经有了一个大小合适的盒子。需要注意的是,如果您的盒子有一半陷在了地板里,或者有一半嵌入了墙中,可以使用Transform(平移)工具(由3个箭头组成,分别是蓝色、红色和绿色)移动盒子让它刚好坐落在地面上。如果您没有看到平移工具,在场景中直接单击盒子即可。
下面使用Geometry Edit(几何体编辑)模式将盒子编辑成门框的形状。参考Unreal Engine 4提供的模板,盒子的高度是190cm左右。即使使用Geometry Edit(几何体编辑)工具也很难精确地测量,所以尝试做到门的高度至少在200cm左右,这样游戏角色才能轻松地穿过。一个测试的好方法是单击Alt+P运行关卡,确认立方体与角色对齐(单击ESC键退出Play-in-editor模式)。
但是当使用Play-in-editor模式时,您可能会发现游戏角色在场景中地板的下面,好像跌入了深渊,或者角色和新建的立方体不在同一个区域(因为此刻的地图被分成了4个区域)。
为解决这一问题,前往Scene Outliner(场景大纲视图,在Unreal Engine 4窗口的右上角),如图38所示。
图38 Scene Outliner(场景大纲视图)窗口
在Scene Outliner(场景大纲视图)窗口中向下滚动找到Player Start,单击它。现在场景视图中,游戏角色已经在被选中,您可以使用Transform(平移)工具将其移动到新建的立方体附近。
然后将立方体编辑成门的形状,下面该把它变成减法BSP了。在此之前,为了进行后面的操作,我们将这扇门复制4次。具体方式是右键(Mac上是Ctrl键+鼠标左键)单击它,在弹出的菜单中选择Edit(编辑)>Copy(复制),如图39所示。这是因为减法BSP虽然可以复制,但是它们在场景中并不明显(只有红色的线框提示),这样很难展示我们的操作。
图39 复制生成的4扇门
4扇门已经创建好,下面把它们放到合适的位置。我将以其中一扇门为例示范如何操作,剩下的就很简单了。单击场景中的任意一面墙,使用平移工具移动选中的这扇门嵌入到这面墙中间,如图40所示。
图40 将门嵌入到墙中
注意:
为了更好地看清楚该屏幕截图,这里对门使用了草坪材质。
在移动门将其嵌入墙的过程中,您可能会发现用作门的这个立方体的厚度不及墙的厚度。为了成功地从墙中凿开一扇门,门的两个面都需要漏在墙的外面,虽然不需要很精确,但至少门的厚度要比墙的厚度大。
如何调整门的厚度呢?还记得Modes(模式)窗口的Geometry Edit(几何体编辑)工具吗?使用该工具调整门的两个面之间的厚度,使得门的前面和后面都漏在墙外面,如图41所示。
图41 用作门的立方体的厚度
注意:
地板设置为透明,为了展示墙的内部,显示门嵌入墙中,并且门的前后都漏在墙外。
将立方体编辑为门的形状,并确定好位置之后,下面就准备将立方体变成一扇门。选中该立方体,Details(细节)面板中显示其属性,如图42所示。Details(细节)面板的默认位置是主窗口的右边,Scene Outliner(场景大纲视图)窗口的下面。
图42 Details(细节)面板
在Details(细节)面板的属性设置中,有一个Brush Settings部分位于面板上方、Search(搜索框)下面。其中第一个选项是Brush Type(画刷类型),默认值是Additive,意思是将BSP添加到场景中。我们想要的是从场景中删除BSP,单击下拉框,在弹出的下拉菜单中选择Subtractive。这时您会看到,之前我们创建的BSP不可见了。与添加BSP不同,Subtractive是指从场景中减去BSP,即删除墙里面的几何体,如图43所示。
图43 Subtractive属性的BSP
注意:
“减法”BSP只对BSP有效,不适用于静态网格!
此刻您会发现地板被减去的门吞噬了一部分,我们将在设置好所有门之后解决这个问题。下面对现在的关卡进行一个快速的测试(Alt键+P键测试,ESC键退出),以保证游戏角色能够穿过这扇门,如图44所示。
图44 关卡测试
下面对余下的这3扇门进行同样的设置操作。为了让角色能够在地图中自由地穿行,为游戏场地中的每一面内墙上都凿出一扇门,如图45所示。创建好之后进行测试,让游戏角色从一个房间开始,穿过所有房间,最后回到起始房间。一旦完成上述操作,就可以继续下面的内容了。
图45 设置好所有门之后的地图
现在我们需要快速地修补地板。首先来解释一下为什么地板上会出现这个洞,应该如何修补。
地板是一个BSP。正如我们之前所介绍的,一个BSP的任何部分如果被设置为减法BSP,那么它将从场景中删除。有时候,您不想使用减法BSP删除所有BSP。例如,带有楼梯的地板上有一个洞,您只希望删除地板上的洞,不想删除上面的楼梯。
解决这一问题比您想象的要容易得多。如果不想删除某个BSP,那么只需要复制它。复制一个BSP然后删除原来的那个BSP是在告诉减法BSP:“我想让这个BSP存在于场景中,不要删除该BSP的任何部分。”
这样的操作看起来非常奇怪,但是事实上,在创建游戏场景时,这是非常有效的方法。它提供了一个额外的工具来增加深度细节,同时在起草关卡时节省了时间。但是在使用该方法时请注意一点,创建完减法BSP之后再复制物体,如果在减法BSP设置好之前复制物体,那么该物体仍然会被删除。如果发生这种现象,再复制一次即可。
下面,让我们来修补地板。选中地板,同时按Ctrl+X组合键(剪切),再同时按Ctrl+V组合键(粘贴),来解决地板被删除这个问题,结果如图46所示。
图46 修补好的地板
上述操作比较省时,因为我们不需要先复制,再找到并删除原来的BSP。
现在是讨论构建光照的时候了。不熟悉Unreal Engine(或者游戏开发本身)的读者可能对此感到困惑。但是不用担心,虽然光照对于项目的视觉效果起着至关重要的作用,但是构建光照本身并不困难。
首先介绍什么是构建光照?
Unreal Engine的光照有几种不同的实现方式。Lightmap(光照贴图)是由静态光照烘焙出来的。模拟场景的真实光照渲染并输出到Lightmap上,在渲染时直接使用,这样就使物体有了光照的感觉。这种做法节省资源,但是物体在移动时不会产生阴影或其他光照效果(如移动的光等)。
动态光照与静态光照正好相反,它耗费资源(没有像静态光照一样使用Lightmap),但是物体移动时有阴影,并且支持光源移动、改变光的颜色等。在我们的示例地图中,已经设置了这种光照。这里使用的是平行光,像太阳一样照亮整个场景,并且一个Lightmass Importance Volume(灯光重要度体积 )环绕在场景周围。
Lightmass Importance Volume(灯光重要度体积)是用来告诉Unreal Engine,静态光照下地图上哪里需要画上阴影。如果您不设置一个Lightmass Importance Volume,那么引擎会为游戏的所有场景计算Lightmap,即使有些部分没有几何体。为什么这样不好呢?因为计算不必要的Lightmap既浪费时间也浪费空间。这就是我们使用Lightmass Importance Volume机制的原因。
为了节省生成文件的空间,我们所需要做的仅仅是保证LIV(Lightmass Importance Volume)环绕您所希望玩家活动的场地。意思是在这个LIV场地,静态光照是高质量,不要浪费不必要的空间。LIV之外的场地不需要高质量的阴影,不要让玩家在Lightmass Importance Volume范围之外活动。
我们的项目已经有了一个Lightmass Importance Volume,并且设置好了平行光照。然而,由于我们把原来的地图弄乱了,添加和删除了一些几何体,所以您会看到我们所设置的阴影已经过时了。您还会看到创建门之后,地板上光照也不一致了。
下面来解决这一问题。请前往主窗口的上方Action(工具栏),如图47所示。这里有一些行为选项,例如Save(保存)、Content(内容)、Marketplace(市场)、Settings(设置)等。
图47 Action(工具栏)窗口
在Action(工具栏)中有一个Build(版本)按钮,位于Matinee按钮(图标是场记板)的右边,Play(播放)按钮(图标是windows窗口前面一个播放图标)的左边。Build(版本)按钮的图标是4个建筑物,其中一个建筑物是深蓝色。单击该按钮,系统将会自动构建现有的光照以及一些其他设置,之后我们会讨论到这一步。
单击该按钮右侧的下拉箭头,弹出一个下拉菜单,可以构建具体的场景元素,例如灯光、智能导航等。还可以改变设置,例如设置光照的质量等。
小窍门:
在项目发布之前,Lighting Quality(光照质量)选择Preview(预览)。这种方式在构建光照时可以节省时间,并且Preview lighting(预览光照)和Production lighting(制作光照)在效果上没有太大差异。再告诉大家一个事实,在开发阶段使用Preview lighting(预览光照)是在保证效果的前提下最快的方法。
如果我们仅仅构建光照,那么我们所需要做的只是单击Build(版本)按钮,或者在下拉菜单中选择Build Lighting Only(仅构建光照)。这时,您的项目就会自动构建光照。屏幕的右下角显示光照构建的进度。当您看到Lighting Build Complete(光照构建已完成),如图48所示,说明光照已经构建完成。
图48 光照构建进度提示
看看现在的阴影是多么丰富,如图49所示。仔细检查这些阴影是否是正确且带有真实感的。如果您对阴影的效果不满意,那么可以在Build(版本)按钮的下拉菜单中随便修改设置直到您满意为止。
图49 构建光照后的阴影效果
回顾一下我们已经完成的内容:根据需求编辑地图、学习BSP的基本知识和接触光照的基本知识。但是我们的冒险游戏才刚刚开始,下面我们学习创建摄像机系统。
在接下来的任务中,为了保证叙述的清晰,我们仅仅使用地图的一部分。除非我额外强调,否则我们的工作区就是地图右下角的方形房间,如图50所示。
图50 任务的工作区
如果PlayerStart当前不在这个房间,那么将其拖进房间,方便下面的操作。
下面我们新建一个Blueprint(蓝图),它是一个可以重复摆放多次的摄像机。无论玩家在地图上的哪个位置,摄像机都会跟随他。想象一下Telltale点击冒险类游戏或者生化危机游戏中的摄像机。
如图51所示,使用简笔画的形式来快速示意。当玩家在房间的左手边时,摄像机面向左侧;当玩家在房间的右手边时,摄像机面向右侧。想象CCTV正在拍摄一个演员,演员扮演的是糖果店里的一个失足青年。
下面重新回到Unreal Engine 4,创建摄像机。前往编辑器左下方的Content Browser(内容浏览器),如图52所示。
在这里可以访问到项目的所有文件。直接拖拽就可以将物体放置到场景中,物体可以是Materials(材质)、Blueprints(蓝图)等。在Content Browser(内容浏览器)中可以导入、编辑和导出文件,这是一个重要功能。
图51 摄像机设置示意图
图52 Content Browser(内容浏览器)
下面创建一个蓝图。首先,新建一个文件夹来存储我们的蓝图,以确保Game文件夹是高亮显示的,这样新建的文件夹就在Game文件夹下,方便查找。单击Game文件夹,它被黄色高亮显示,说明被选中,如图53所示。
单击Content Browser(内容浏览器)上方的Create(创建)按钮,弹出一个下拉菜单,选择Create Folder(新建文件夹),在Game文件夹中出现了一个新文件夹,如图54所示。
图53 Game文件夹选中状态
图54 新建文件夹
文件夹刚刚新建时处于选中状态,如图55所示。此时可以编辑文件夹的名字,这里命名为ArtOfBP。
图55 处于选中状态的文件夹
注意:
如果不小心点击了文件夹,文件夹的名字不再处于编辑状态了。右键(Mac上是Ctrl键+鼠标左键)单击文件夹,在弹出菜单中选择Rename(重命名)即可。或者选中该文件夹,然后单击F2键。
双击打开该文件夹,如图56所示。
图56 打开新建文件夹ArtOfBP
因为当前在文件夹下,所以使用Create(创建)按钮创建蓝图时,新建的蓝图将位于该文件夹下,节省了文件夹之间移动的时间。单击Create(创建)按钮选择Blueprint(蓝图),如图57所示。
图57 新建Blueprint(蓝图)
这时弹出一个Pick Parent Class(选择父类)窗口,如图58所示,选择新建蓝图的父类。
图58 Pick Parent Class(选择父类)窗口
乍一看这个窗口,您可能会有点困惑,下面简单解释一下:如果您选择一个苹果作为父类,那么创建蓝图时会自带一颗苹果核;如果您选择一个橘子,那么苹果核会换成橘子的种子。这种创建方式简单易于操作,与某些时候要花费一整天时间从头创建相比,选择一种风格作为父类来创建蓝图将大大节省时间。
每一个父类都有简单扼要的描述,说明该父类是什么,可以实现什么功能。所以花一两分钟阅读一下描述内容,在您之后的项目中会有很大帮助。
在我们的项目中,需要Actor类的蓝图。这是因为Actor是一个可以在游戏世界中独立生存的对象,场景中的每一个对象(这里不包括BSP)都被称为Actor(而不是objects)。选择Actor按钮创建蓝图。将该蓝图命名为BP_Camera,如图59所示,表示一个摄像机的蓝图,方便将来查找。这仅仅是我个人项目的命名方式。
当我创建材质时,以“M”为前缀命名,Animation Blueprints以“AnimBP”为前缀。当我需要查找它们,但是又记不清它们的名字时,只要我记得文件类型,就可以使用Content Browser(内容浏览器)的内置搜索功能很容易找到它们。
已经创建好蓝图,下面按照我们需要的功能编辑它。
双击BP_Camera打开蓝图编辑器,界面默认处于Component(组件)视图。蓝图编辑器分为3部分:Defaults(默认值)、Component(组件)和Graph(图表)。Defaults(默认值)视图是用来设置蓝图的默认选项的;Component(组件)视图是在蓝图中设置对象的;Graph(图表)视图是为蓝图编写代码的。有一个简单的方法可以记住这些,就是Settings(设置)—Objects(对象)—Code(代码)。
图59 创建蓝图
确保当前处于Component(组件)视图。为了找到当前处于哪种视图,查看蓝图编辑器窗口的右上方。有一些导航按钮,其中橘黄色高亮显示的就是当前被激活的按钮,如图60所示。
图60 蓝图Components(组件)视图
在屏幕的左边,有一个类似Content Browser(内容浏览器)的窗口,叫做Components(组件),是用来为蓝图添加组件和对组件排序的。
现在,有一个Root组件叫做[ROOT] DefaultSceneRoot。什么意思呢?Root组件是所有组件的HomeBase(根容器)。打个比方,扔一个拴着绳子的球,HomeBase就是抛出去的那只手。但是为什么要把球拴在绳子上呢?因为这个绳子将会告诉我们球在哪里(这时球已经飞出了我们的视线),以及球如何再回到手中(如果您想再抛一次球的话)。
现在我要抛一个曲线球:只要我们添加一个组件,DefaultSceneRoot就会被重写,“绳子”就丢失了。您一定会问:为什么在删除DefaultSceneRoot时没有提示我?很简单,即使丢失了DefaultSceneRoot,我们也可以手动将其添加回来,所以可以选择是否需要“绳子”。
您知道系统为什么是这样设置的吗?乍一看似乎很复杂,但当你将其分解,它又非常简单。当没有组件的时候,蓝图系统给我们一个Root组件,这样在不需要组件的情景中,我们可以编写其他任何代码。然而,当您创建一个蓝图,在该蓝图下您需要组件时,蓝图系统会删除这个Root组件,然后让您选择是否需要“绳子”。
回到我们的项目中,前往Component(组件)视图,单击Add Component(添加组件)按钮。在弹出的下拉菜单中搜索Scene,选择插入一个Scene组件,如图61所示。Scene组件就好比绳子。
图61 添加Scene组件
可以选择为它重命名或者使用默认值。当您看到[ROOT] Scene1(或者您的命名),表示Scene组件已经创建成功,下面我们继续添加Camera(摄像机)。
如何添加Camera组件呢?与添加Scene组件一样,单击Add Component(添加组件)按钮,选择Camera,如图62所示。
图62 添加Camera组件
同样,您可以选择为它重命名或者使用默认值。此刻,您的Components(组件)窗口如图63所示。
图63 Components(组件)窗口
什么意思呢?Root scene是Home Base(根容器),Camera是根的“孩子”。孩子最终要离开家。正如我们之前讨论的,Root是绳子,Camera是球。无论ROOT Scene在游戏世界的哪里,Camera会一直与Root保持同样的距离,Scene总是知道Camera在哪里,反之亦然。
现在,在我们蓝图中已经有了组件,下一步就是为蓝图编写代码,告诉蓝图要做什么。在没编写代码之前,如果我们将组件拖拽到场景中,它只会待在那里什么也不做。
到屏幕的右上方,使用导航按钮前往Graph(图表)视图,如图64所示。
图64 蓝图的导航按钮
当前我们位于Graph(图表)视图,是时候进行一些有趣的操作了。
重要提示:
本书从现在起,当我告诉您要创建一个节点时,默认是使用Compact Blueprint Library(CBL)来搜索和创建(除非额外说明)。右键(Mac上是Ctrl键+鼠标左键)单击蓝图Graph(图表)视图空白处打开CBL,在Search(搜索)框中输入节点名称。
首先,我们需要一个Tick事件。什么是事件和Tick事件?
什么是Event(事件)?蓝图中的事件正如字面意思所描述的,就是发生一个事件。如果蓝图中没有事件,那么任何事情都不会发生。例如,想一下宇宙大爆炸原理:一旦宇宙大爆炸事件发生,那么各式各样的Action(动作)会因此发生。如果没有动作连接到蓝图的事件,那么就不会触发该动作,也不会执行该动作。
当创建蓝图的时候,记住在蓝图动作发生之前,要先发生事件。您可以通过如下简单的方式来区分蓝图中的Event(事件)节点和Action(动作)节点:事件只有输出引脚(通常在右边),用红色表示;而动作有输入引脚和输出引脚,用蓝色表示。
所以,红色 = Event(事件),蓝色 = Action(动作)。
什么是Tick事件?Tick事件是指在游戏时间的每一帧都被触发的事件。游戏开发的新手可能不明白这是什么意思,特别是帧和秒的区别。但是多数人知道一帧不等于一秒,它比一秒要快。
您曾经测试过一个游戏的性能吗,或者有意购买达到一定FPS(Frame Per Second)游戏的电脑部件?回想一下,当讨论游戏时,会经常提到过30FPS或60FPS。触发Tick事件是一帧,所以60FPS是指触发连接到它的60个Tick事件。
我们已经学习了什么是Tick事件,现在就使用Tick事件控制摄像机的位置,让它对准玩家。
下面从何开始呢?蓝图的脚本从哪里开始?从事件开始!针对当前需求,我们使用刚刚学习的Tick事件。
在开始编写脚本之前,确认现在位于脚本界面的正确区域。在Debug filter(调试过滤)区域可以查看所在的区域,您会看到两个选项卡:Construction Script和Event Graph(事件图表),如图65所示。
Construction Script选项卡是编写蓝图初始化代码的地方。例如,设置蓝图的Mesh(网格对象),告诉蓝图在特定情况下的行为,等等。
Event Graph(事件图表),如图66所示,是编写由事件所触发的代码的地方。这些代码既可以被当前蓝图触发,也可以被另外一个蓝图远程触发。
图65 蓝图的Graph(图表)视图
图66 蓝图EventGraph(事件图表)选项卡
经验表明,90%的情况下您会使用EventGraph(事件图表)选项卡,因为Construction Script选项卡不能与游戏世界及其他蓝图进行交互,但是在EventGraph(事件图表)选项卡中可以。您可以在这两个选项卡之间切换。如果选项卡的图标颜色为浅灰色,说明可以选择该选项卡。如果为深灰色,意思是该选项卡没有被激活。
正如前面所说,我们需要一个事件,因为如果没有触发事件,就不能执行任何代码。这里需要每一帧都触发一段代码,所以使用Tick事件。
下面在Event Graph(事件图表)选项卡中创建Tick节点。右键(Mac上是Ctrl键+鼠标左键)单击蓝图Graph(图表)视图空白处,打开CBL(Compact Blueprint Library),人工寻找或者在Search(搜索)框中输入节点名称,如图67所示。
图67 在CBL中搜索Event Tick
单击Event Tick(事件Tick)来新建节点,如图68所示。
图68 Event Tick(事件Tick)节点
下面我们解释一下节点上所有图标的含义。
首先,您会注意到文本Event Tick(事件Tick)的背景是红色,意思是这是一个Event(事件),而不是Action(动作)。此外,文本Event Tick(事件Tick)左边有一个中间含有箭头的菱形图标,也是用来标识这是一个事件的。
其次,您还会观察到文本Event Tick(事件Tick)的右边有一个镶有亮红色边框的黑色正方形。这个图标的含义是Output Delegate(输出委托)。我之后再解释它的意思,因为涉及很多现在还没有讲解到的知识。
在红色背景的下方有两个图标,一个指向右边的空箭头和一个指向右边的绿色空圆圈。在解释它们的含义之前,注意它们的位置。对于节点来说,输入和输出是通过它们在节点中的位置来区分的。左边的是输入,右边的是输出。这将帮助您来区分节点是事件还是动作,事件只有输出(也就是只有在右边的图标),而动作既有在左边的图标也有在右边的图标。
扼要重述一下:节点左边的图标表示输入,右边的图标表示输出。
与输出连接的是什么呢?输入。例如,将键盘的USB插入到电脑的USB接口上。把敲击键盘看作是一个事件,这个事件触发的行为通过USB接口输出到电脑。
上述这个例子很好地说明了蓝图的工作原理:事件>事件输出>动作输入>动作。但是这里缺少了一个重要的东西——事件>动作的关键因素,就是execution pin(执行引脚)。Event Tick(事件Tick)节点的红色背景下方有两个图标,其中一个是白色的空心箭头图标,就是这里所说的执行引脚。
执行引脚到底是什么呢?执行引脚就是操作的脉络,它将事件的能量传递给与它连接的节点。例如,事件节点是一个完整的电路,而动作节点是缺少了电源的电路,您可以使用事件的执行引脚输出能量给动作节点使其工作。那么如果有两个动作节点呢?没问题。虽然动作节点需要从事件节点传递的能量,但是它不需要对这个能量做任何操作,仅仅用来确认“我收到信号了,现在可以运行了”。所以如果让两个动作节点同时工作,就将一个事件节点通过执行引脚连接到其中一个动作节点,再将另外一个动作节点连接到这个动作节点的输出,它们将同时使用事件节点的能量(因为没有能量丢失)。
下面我们来实际操作一下。首先新建一个我们需要的节点。因为摄像机总是面向玩家,所以新建节点Set World Rotation。将这个节点与一个Event Tick(事件Tick)节点连接,用来改变每一帧摄像机的角度。
新建Set World Rotation节点。如果您使用的是4.6或以上版本的Unreal,将会在CBL中看到“Set World Rotation (Camera1)”(或者是您的摄像机名称),如图69所示。
图69 新建Set World Rotation节点
注意:
如果您使用的是低于版本4.6的Unreal Engine,您看到的是Set World Rotation,需要手动设置Camera1,通过将Camera1(在蓝图视图左边的变量库中)拖拽到新建节点的Target(对象)引脚上。在一些更老的版本中,需要您将Camera1从变量库中拖入,然后从Target(对象)引脚向外拖拽,再输入Set World Rotation。
如果使用的是4.6或以上版本,直接右键(Mac上是Ctrl键+鼠标左键)单击打开Compact Blueprint Library,搜索Set World Rotation,然后选择Set World Rotation (Camera1)。
新建的Set World Rotation节点如图70所示。
正如之前所说,动作是与事件相连的。具体操作是将Event Tick(事件Tick)节点的输出执行引脚与Set World Rotation (Camera1)的输入执行引脚相连,如图71所示。当空心的执行引脚被白色填充,同时两个引脚之间有一条线相连时,说明已经建立了连接关系。
图70 创建的Set World Rotation节点
图71 事件节点与动作节点连接
下面我们将设置每一帧摄像机的World Rotation(旋转角度)。仔细观察刚刚创建的节点,发现我们需要计算出摄像机的角度(当前是Roll = 0,Pos = 0,Yaw = 0),以便摄像机跟着玩家旋转。
下面用代码来实现摄像机跟随玩家。当前我们要创建的对象没有执行引脚,这和我们之前讲解的内容完全不同,这是因为我们将要创建的不是动作节点。创建完后面的代码,我们再回来解释它是怎么工作的。
下面将要编写的这段代码连接到Set World Rotation (Camera1)的New Rotation。注意要保证蓝图有足够大的空间,否则因为蓝图中有许多线交叉连接,很快会使代码变得杂乱难读。
在编写蓝图代码之前,前往左边的变量库,在Components(组件)下面找到Camera1(或者是您的摄像机名字),如图72所示。
图72 My Blueprint(我的蓝图)面板
单击文本Camera1,将这个变量拖入到蓝图中。此时将弹出一个小菜单,询问是Get(获得)还是Set(设置),如图73所示。意思是获得变量,还是设置变量。在当前情况下,它是一个新的摄像机Actor,所以选择Get(获得)。
图73 向蓝图中拖入变量时弹出的菜单
选择Get(获得)之后,蓝图中将出现一个蓝色底的圆角矩形,并且带有一个蓝色的输出引脚,如图74所示。如果您看到的不一样,说明您在从变量库中拖入Camera 1变量时,选择的不是Get(获得),应返回重新操作。
图74 Get(获得)状态的Camera 1变量
单击Camera 1节点上的蓝色输出引脚,向右拖拽,这时将打开Compact Blueprint Library。由于我们需要摄像机的旋转角度,所以输入Get World Rotation,如图75所示。
图75 拖拽Cameara 1节点上的蓝色输出引脚时打开的Compact Blueprint Library
找到Get World Rotation节点之后,单击新建节点,如图76所示。当前这个节点应该已经与Camera1建立了连接,如果没有,要先建立连接。
图76 创建Get World Rotation节点
我们得到了游戏世界中摄像机的旋转信息,例如它是绕X轴旋转45°,绕Y轴旋转51°,可以用Rot(X) = 45,Rot(Y) = 51来表示。但是在我们的例子中只需要知道旋转后X轴的方向,就可以轻松跟踪摄像机当前的朝向。
使用CBL新建一个Get Rotation XVector节点,将其连接到Get World Rotation节点的输出引脚,如图77所示。
图77 新建Get Rotation XVector节点,并与Get World Rotation节点相连
现在,我们获得了摄像机X轴的朝向信息。从技术角度来讲,因为还没有连接到事件的主要链条上,所以此刻还不能工作,但是理论上,一旦与事件的主要链条连接上,我们就可以获得摄像机的信息。目前这些只是摄像机跟随玩家这个功能的部分代码。
下面我们将目前收集到的信息(摄像机的X向量值)连接起来,让摄像机跟着移动。但是我们希望摄像机的移动轨迹平滑一些,使用VInterp To节点实现这一功能。该节点可以创建两个值之间的平滑过渡。
使用Compact Blueprint Library新建VInterp To节点(注意不是VInterp To Constant),将其Current引脚与Get Rotation XVector节点的输出引脚相连,如图78所示。
图78 新建VInterp To节点,并与Get Rotation XVector节点连接
VInterp To节点有3个输入,需要设置好这3个值才算完成了这个节点的创建。我们一会儿再讨论Target输入,先关注Delta Time 和 Interp Speed这两个输入。设置Interp Speed为0.01,意思是每隔0.01的Delta Time(我们一会解释它的意思)就更新当前的Rotation(旋转)值,并将其赋值给Target。设置VInterp To节点的Interp Speed值为0.01,如图79所示。
图79 设置VInterp To节点的Interp Speed值为0.01
有两种方式设置Delta Time值,我们先解释一下什么是Delta Time。
Delta Time是从上一个Tick(或者上一帧)到此刻所经历的时间。还记得我们之前见过Delta Time吗?它曾在Event Tick节点中出现。
有两种方式连接到Event Tick节点的Delta Time,单击Event Tick节点的Delta Time输出,拖拽到Vinterp To节点的Delta Time输入,如图80所示。
图80 设置VInterp To节点的DeltaTime值
从图80可以看出,构建的蓝图特别凌乱。虽然现在还不是问题,但是当我们创建更复杂的蓝图时,就很难分辨出这些节点之间的连接关系了。
所以,我们将Delta Time存储为一个变量,这不仅能使蓝图更清晰,还可以随时使用Delta Time。我知道有些读者可能会说这样意义不大,但是实际上将Delta Time转变为一个变量有很多好处:
1.保持蓝图代码清晰、可读性强;
2.有助于多次使用Delta Time值;
3.有助于将一些蓝图节点拆封成单独的图(之后会讲解到);
4.清晰整齐的蓝图意味着清晰的思路。
如果两个Delta Time已经连接,那么断开连接。具体操作是Alt键+鼠标左键单击连接的任意一端引脚,下面采用更恰当的操作方式。
感谢版本4.6的改进,现在有一种特别简单的方式将Delta Time转变为变量,之后就可以随时使用Delta Time了。
在4.6或以上版本,右键(Mac上是Ctrl键+鼠标左键)单击Event Tick节点的Delta Time的输出引脚,选择Promote to Variable(提升为变量),新建一个Set New Var(设置New Var)节点,如图81所示。同时在界面左边的变量库中也新建了一个NewVar变量。
图81 新建Set New Var(设置New Var)节点
需要注意几点。首先,您会看到Set World Rotation节点中出现“ERROR!”。别担心,这不是错误。只需要单击蓝图视图中工具栏左上方的Compile(编译)按钮(图标是两个齿轮上面有一个画有问号的矩形框),重新编译一下,这个问题就解决了。
其次,Set New Var(设置New Var)节点没有与事件的主要链条(或者说是蓝图的能量线)相连。Alt键+鼠标左键单击Event Tick的输出执行引脚或者Set World Rotation节点的输入执行引脚,断开连接,然后将Event Tick的输出与Set New Var(设置New Var)节点的输入相连,Set New Var(设置New Var)节点的输出与Set World Rotation节点的输入相连,如图82所示。
图82 设置Set New Var(设置New Var)节点与Event Tick节点和Set World Rotation节点的连接方式
Delta Seconds是基于时间的变量,这一步操作是保证对于每一帧,我们在进行任何操作之前都先设置Delta Seconds,这对于后面获取Delta Seconds值至关重要。
最后一个问题是变量的命名。因为很容易忘记New Var表示什么,所以将其命名,以方便记忆。前往蓝图视图左边的变量库,单击新建的New Var变量,在Details(细节)面板中出现该变量的各种选项。其中第一个选项是Variable Name(变量名称),当前默认值是New Var。将New Var重命名为DT_DeltaTime,如图83所示。单击键盘上的Enter(回车)键,编译蓝图(单击工具栏左上方图标为贴有问号矩形框的两个齿轮的按钮)。编译完成后,单击编译按钮右边的Save(保存)按钮,保存上述操作。
图83 命名变量
如果您使用的是Unreal Engine 4的旧版本(低于4.6),就不能直接对Event Tick节点的Delta Time使用Promote to Variable(提升为变量)。而是要在变量库中手动创建变量,设置其为浮点数(稍后解释原因),将其拖拽到蓝图中并选择Set(设置)。设置好之后,重复之前的步骤连接到执行主链上。在版本4.6之前,您还需要进行一步操作:从Event Tick节点的Delta Time引脚拖出,连接到Set New Var / DT_DeltaTime节点的输入引脚。但是如果使用的是版本4.6或以上,使用Promote to Variable(提升为变量)可以跳过这一步。
现在已经有了DT_DeltaTime变量,将变量库中的DT_DeltaTime变量拖到VInterp To节点DeltaTime引脚的上面,或者将DT_DeltaTime变量拖到蓝图区域,选择Get(获得)选项,然后将其与VInterp To节点的DeltaTime引脚相连,如图84所示。
图84 DT_DeltaTime变量与VInterp To节点DeltaTime引脚相连
现在,我们来处理VInterp To节点的Target输入。Target的作用很明显,是输入Current的变换目标。举例来解释:如果Current是1,Target是5,VInterp节点利用Delta Time 和 Interp Speed生成1到5的序列。因为每一秒触发一次,所以可以保证平滑过渡,避免抖动。
新建用于Target输入引脚的节点,将变量库中的变量Camera 1(或者是您摄像机的名称)拖入到蓝图区域,选择Get(获得)选项,如图85所示。
图85 变量Camera 1拖入到蓝图区域
右键(Mac上是Ctrl键+鼠标左键)单击打开CBL,输入Get Player,选择Get Player Character,如图86所示。
图86 在CBL中搜索Get Player Character
现在得到了一个可以调用游戏当前玩家的节点和对应的Player Blueprint(玩家蓝图,稍后将详细解释),如图87所示。
图87 创建的Get Player Character节点
下面需要得到它们在游戏世界中的位置。打开CBL,输入Get Actor搜索得到Get Actor Location节点。将该节点的输入与Get Player Character节点的Return Value引脚相连,如图88所示。
图88 创建的Get Actor Location节点
单击刚才创建的Camera 1节点的输出引脚,向右拖拽打开Compact Blueprint Library,输入Get World搜索,选择Get World Location,如图89所示。
图89 创建的Get World Location节点
现在已经得到了摄像机和玩家在游戏世界中的位置信息(因为我们使用的是Tick事件,所以每一帧都会更新这些信息)。下面让这两个位置相减。为什么呢?因为我们不希望摄像机紧跟着玩家,而是两者之间保持一定的距离,摄像机和玩家之间的距离向量将提供平滑的显示效果,在玩家突然做一个动作(如跳高或者快速转身)时,摄像机不会跟着玩家快速移动。
打开CBL,输入Vector,选择Vector – Vector,如图90所示。
图90 新建Vector – Vector节点
Vector – Vector节点有两个输入和一个输出,将Get Actor Location的输出与Vector – Vector节点中的一个输入相连,Get World Location的输出与另外一个输入相连,如图91所示。
图91 设置Vector – Vector节点的输入
将Vector – Vector节点的输出连接到VInterp To节点的Target输入,如图92所示。
图92 设置Vector – Vector节点的输出
现在,已经得到了摄像机的旋转信息,并且通过玩家和摄像机之间的平滑变换对其赋值。
下面将之前计算的旋转进行分解,得到其中的pitch和yaw值(上下及四周旋转分量),并加以截断限制,防止旋转的角度过大。对这些值进行截断限制之后,重新计算得到一个旋转值,作为之前创建的Set World Rotation节点的输入。
我发现刚才的操作中有一个错误。如果不纠正这个错误,摄像机将背离玩家,而不是面向玩家。请您花一点儿时间仔细查看代码,尝试找到错误的位置。
现在我们在它成为一个真正的问题之前,快速找到并解决它。先来思考一个数学问题,有两个数100和51,让它们做减法。可以100 − 51 = 49或者51−100 = −49。由于这两个数的先后位置不同,结果截然不同。
现在,回到获取Camera(摄像机)位置和Player Controller(玩家控制器)位置这部分代码。这两个值相减之后的结果是VInterp To节点的Target输入,如图93所示。
您的摄像机的Get World Location是与Vector – Vector节点的第一个输入引脚相连吗?如果是,说明您准确无误地跟着本书的讲解步骤,但是这里仍包含一个错误!很庆幸在它成为一个真正问题之前,我把它指出来了。这是一个很好的机会,让大家看到这个步骤是多么容易混淆,容易发生错误。
假如我们得到的摄像机的值是X=51、Y=11和Z=22,减去玩家的坐标值。因为玩家距离更远一些,所以它的坐标值往往比摄像机的坐标值大,例如X=151、Y=211、Z=512。如果这两者做减法,将得到一个负值。这意味着什么呢?这导致的效果是摄像机将远离玩家,而不是面朝向他。
图93 VInterp To节点的Target输入的连接关系
那么如何解决这个问题呢?很简单!将玩家的Get Actor Location节点与Vector – Vector节点的上方输入相连,摄像机的Get World Location节点与Vector – Vector节点的下方输入相连,如图94所示。
图94 VInterp To节点的Target输入的连接关系
解决了这个问题为我们后面节省了大量的时间,不用为出现类似于“为什么运行不对”这样的错误而烦恼了。
总之,解决完这个问题,我们继续编写代码。现在需要使用VInterp To节点的输出重新设置旋转。右键(Mac上是Ctrl键+鼠标左键)单击打开CBL,输入Make Rot,选择Make Rot from X,如图95所示。
图95 搜索Make Rot from X节点
将新建的Make Rot from X节点的X输入与VInterp To节点的输出相连,如图96所示。
图96 Make Rot from X节点与VInterp To节点的连接关系
现在,我们已经得到了旋转信息,它由X轴转向信息计算而得。下面将对旋转进行分解,对其中的pitch和yaw分量进行限制。为什么呢?我们之前提到过,这么做是为了确保摄像机在一定的范围内旋转从而不会失去控制。
图97是一幅草图,来解释它是什么意思:假设最外围的矩形框是地图区域,底部中间的矩形是摄像机,顶部中间的黑点是玩家,中间的锥形区域是我们希望摄像机关注的区域,而两边的锥形区域是不希望摄像机拍摄的地方。
图97 摄像机位置示意图
现在摄像机已经被准确控制了。等到最后完成这个项目,效果就会清晰地呈现出来。
现在需要分解前面获得的旋转。前往Compact Blueprint Library新建Break Rot(而不是Break Rot into axes)节点,将其与Make Rot from X节点的输出相连,如图98所示。
新建两个Clamp Angle节点,在搜索框中输入Clamp Angle得到常用的Clamps(不是Clamp [Float]),如图99所示。
将Break Rot节点的Pitch输出与上面的Clamp Angle节点的Angle Degrees输入相连,将Break Rot节点的Yaw输出连接到下面的Clamp Angle节点的Angle Degrees输入,如图100所示。
图98 创建的Break Rot节点
图99 创建的两个Clamp Angle节点
图100 两个Clamp Angle节点的连接方式
为了计算这两个Clamp angle的Min / Max Angle Degrees值,需要做一点点数学运算。别担心,我们不需要计算出结果,仅仅列出等式即可。我们将在等式中使用Pitch和Yaw这两个值和一个常数80。为什么选择80呢?意思是摄像机在面向玩家时,限制摄像机的角度在−80°到+80°之间,也就是我们希望摄像机关注的160°区域(这样设置是为了不让其关注整个屏幕,同时避免玩家突然运动时,摄像机找不到他)。
有两种方式将常数80加入到我们的蓝图中。一种是使用Make Literal Float节点,另一种方式是在变量库中新建一个Variable(变量,Float类型,即浮点类型的变量),设置其Default Value(默认值)为80。注意新建变量之后,Compile(编译)并Save(保存)之后就可以设置变量的Default Value(默认值)了。
根据您的个人喜好选择一种方式。我在这里新建Make Literal Float节点,并设置它的值为80。然后将Variable(变量)或者Make Literal Float节点复制4次,如图101所示。
图101 新建4个Make Literal Float节点
新建两个Float – Float节点和两个Float + Float节点。将这4个节点与Make Literal Float节点(或者您的变量节点)相连,注意是将Make Literal Float节点(或者您的变量节点)连接到Plus / Minus(−/+)节点的第二个输入。
下面将第一个和第三个Make Literal Float节点(或者您的变量节点)连接到两个Float – Float节点的第二个输入,如图102所示。
图102 两个Float – Float节点的连接方式
将第二个和第四个Make Literal Float节点(或者您的变量节点)连接到两个Float+ Float节点的第二个输入,如图103所示。
图103 两个Float + Float节点的连接方式
如果您看不清这些图片,记得从http://www.kitatus.co.uk免费下载本书插图的高清版本。再次确认您的蓝图中,4个Make Literal Float节点或者变量节点的连接方式如下:
1.Make Literal Float节点/变量节点>Minus(−)节点的第二个输入;
2.Make Literal Float节点/变量节点> Plus(+)节点的第二个输入;
3.Make Literal Float节点/变量节点>Minus(−)节点的第二个输入;
4.Make Literal Float节点/变量节点> Plus(+)节点的第二个输入。
下面回到Break Rot节点,虽然该节点的Pitch和Yaw输出已经与两个Clamp Angle节点的输入连接了,我们仍然可以将其与其他输入连接,即可以一个输出同时与多个输入相连。
下面将第一个Minus(-)节点和第一个Plus(+)节点的第一个输入与Break Rot节点的Pitch输出相连,第二个Minus(-)节点和第二个Plus(+)节点的第一个输入连接到Break Rot节点的Yaw输出,如图104所示。
图104 Break Rot节点的Pitch和Yaw输出与Minus(-)和Plus(+)节点的连接方式
现在设置这些Minus(-)和Plus(+)节点的输出。下面列出Clamp Angle节点的Min Angle Degrees / Max Angle Degrees输入的连接方式,如图105所示。
图105 Clamp Angle节点的Min Angle Degrees / Max Angle Degrees输入的连接方式
1.第一个Minus(-)节点的输出连接到第一个Clamp Angles节点的Min Angle Degrees引脚;
2.第一个Plus(+)节点的输出连接到第一个Clamp Angles节点的Max Angle Degrees引脚;
3.第二个Minus(-)节点的输出连接到第二个Clamp Angles节点的Min Angle Degrees引脚;
4.第二个Plus(+)节点的输出连接到第二个Clamp Angles节点的Max Angle Degrees引脚。
我们的蓝图看起来有点像一份美味的意大利面汤了。只要您跟着我的步骤操作,一切都会很顺利的。我们很快就要完成这个蓝图了,下面利用这些信息为摄像机生成旋转。
右键(Mac上是Ctrl键+鼠标左键)单击打开Compact Blueprint Library,搜索Make Rot,选择新建Make Rot节点,如图106所示。
图106 创建的Make Rot节点
将第一个Clamp Angle节点的输出与新建的Make Rot节点的Pitch输入相连,将第二个Clamp Angle节点的输出与该Make Rot节点的Yaw输入相连,如图107所示。
最后,我们得到了一个旋转输出(通过引脚颜色可以知道当前正在处理的输出类型)。将Make Rot节点的Return Value输出与很久之前创建的Set World Rotation节点的New Rotation输入相连,如图108所示。
在完成这个蓝图之前,仅剩下两件事情!
前往Set World Location节点,单击节点下方的向下箭头,展示隐藏选项,如图109所示。
图107 Make Rot节点的Pitch和Yaw输入的连接方式
图108 Make Rot节点的Return Value输出的连接方式
图109 展开Set World Location节点的隐藏选项
现在您会看到一个名为Sweep的选项,当前状态是Off(关闭)。单击空复选框激活这个选项,框中有一个勾号,如图110所示,说明Sweep已经被激活了。
图110 激活Set World Location节点的Sweep选项
Sweep是做什么用的呢?Sweep是用来保证,当摄像机被障碍物(例如墙)挡住时,它不会继续移动。
现在还剩下最后一件事情:编译和保存。编译按钮位于该窗口的左上方,图标是两个齿轮上面有一个矩形框。编译前,矩形框中是一个问号。编译完,矩形框中是一个勾号。
单击Compile(编译)按钮,编译完成后,单击Compile(编译)按钮右边的Save(保存)按钮,如图111所示。
图111 编译完的Compile(编译)按钮和Save(保存)按钮
这个蓝图已经完成。现在继续项目,关闭蓝图,返回到Unreal Engine 4的主窗口。此刻,我们虽然创建好了蓝图,但是还没有显示在场景中,也就是没有被激活。下面我们马上来测试它。
前往Content Browser(内容浏览器),将BP_Camera拖拽到场景中。您可以把它摆放在场景中的任何位置,只要玩家和视图没有被其他障碍物挡住即可。使用Transform(平移)工具设置摄像机的位置,直到您满意为止,如图112所示。
图112 设置摄像机在场景中的位置
现在在Level Blueprint(关卡蓝图)中添加一些代码,将摄像机设置为Active(激活)状态。
什么是Level Blueprint(关卡蓝图)?Level Blueprint(关卡蓝图)是一种特殊的蓝图模式,适用于当前正在玩的关卡或者正在运行的地图。您可以在一个Level Blueprint(关卡蓝图)中嵌入代码来记录分数或者跟踪Actor的状态等。
在继续之前,确保BP_Camera已经摆放在了场景中。通过如下方法检查:选中摄像机,它的周围会出现橘黄色的边缘线,并且旁边出现Transform(平移)工具(通常在该对象的中间)。
单击场景视图上方工具栏中的Blueprints(蓝图)按钮,选择Open Level Blueprint(打开关卡蓝图),如图113所示。
图113 Open Level Blueprint(打开关卡蓝图)选项
单击Open Level Blueprint(打开关卡蓝图),打开关卡蓝图。右键(Mac上是Ctrl键+鼠标左键)单击打开CBL,如果场景中的BP_Camera处于选中状态,那么在Compact Blueprint Library的上方有一个Create a Reference to BP_Camera(创建一个到BP_Camera的引用)选项,如图114所示。单击创建一个场景中摄像机的引用节点。
图114 CBL中的Create a Reference to BP_Camera(创建一个到BP_Camera的引用)选项
如果您没有看到Create a Reference to BP_Camera(创建一个到BP_Camera的引用)选项,说明没有选中场景中的摄像机。那么,返回Unreal Engine主窗口,选中场景中创建的BP_Camera对象。重复之前的步骤,直到在Level Blueprint(关卡蓝图)中添加了BP_Camera的引用节点,如图115所示。
图115 BP_Camera的引用节点
现在需要新建一个节点,用于接收BP_Camera节点的输出(BP_Camera节点上没有输入和执行引脚)。将要创建的这个节点现在对我们不可见。为了访问到这个节点,不得不暂时关闭CBL中的Context Sensitive(情境关联)。
什么是Context Sensitive(情境关联)?Context Sensitive(情境关联)是Compact Blueprint Library窗口中的一个按钮,功能是根据当前的情境自动过滤菜单中的选项。也就是说,因为在特定的情景下,可能只需要特定的节点,菜单中不显示所有的选项。
关闭Context Sensitive(情境关联)模式意味着,我们能看到所有可以放置在蓝图中的节点。这时CBL的视图看起来有些混乱,即使对经验丰富的蓝图专家也是如此,因此在不必要的情况下还是建议打开Context Sensitive(情境关联)模式。
下面打开Compact Blueprint Library,取消CBL右上角方框内的勾选,关闭Context Sensitive(情境关联)模式,如图116所示。
图116 关闭CBL的Context Sensitive(情境关联)
Context Sensitive(情境关联)已经关闭,在搜索框中输入Set View Target,选择Set View Target With Blend,如图117所示。
图117 在CBL中搜索Set View Target With Blend
如图118所示,Set View Target With Blend节点看起来很复杂。但是一句话总结这个节点就是,Set View Target(With Blend)是一个设置当前活动摄像机的节点。
图118 Set View Target With Blend节点
只需要关注该节点的3个引脚,输入执行引脚,Target引脚和New View Target引脚。注意到New View Target引脚就是待设置的新摄像机,所以将BP_Camera节点的输出与New View Target引脚相连,如图119所示。
图119 BP_Camera节点的输出与New View Target输入相连
Target引脚默认引用当前摄像机,这里我们想用BP_Camera来代替它。打开Compact Blueprint Library,重新勾选Context Sensitive(情境关联),输入Player,选择Get Player Controller创建节点。将Get Player Controller节点的输出与Set View Target with Blend节点的Target输入相连,如图120所示。
图120 新建的Get Player Controller节点的输出与Set View Target with Blend节点的Target输入相连
还有一步操作就要完成了。还记得最开始我们讲到蓝图时提到的内容吗?每一个动作需要有(或者至少有)一个事件触发。当前还没有任何事件连接到Set View Target With Blend节点,所以它将不会被触发。
打开CBL,输入Begin,选择Event Begin Play。每当游戏开始时,该事件就会被触发一次,这将很好地测试BP_Camera是否正常工作。
前往CBL新建Event Begin Play节点,将其输出执行引脚与Set View Target with Blend的输入执行引脚相连,如图121所示。
图121 新建Event Begin Play节点,将其输出执行引脚与Set View Target with Blend的输入执行引脚相连
单击Compile(编译)和Save(保存)按钮,关闭该窗口。
下面测试摄像机是否正常工作!找到位于场景视图上面的工具栏(打开Level Blueprint的地方)中的Play按钮,单击其下拉箭头,选择New Editor Window选项,如图122所示,可以测试我们的项目。
图122 选择工具栏中Play按钮下拉菜单中的New Editor Window选项
测试项目时,您的BP_Camera应该可以正常工作。如果没有,请返回到本步骤的开始,确保所有的步骤正确完成。或者到http://www.kitatus.co.uk 中免费下载该项目文件,与你的项目做比较,下载文件名为“[LESSON1]ArtOfBP_01.zip”!
您已经完美地实现了第一个蓝图项目。现在在此基础上扩展一点,在地图上设置多个摄像机,营造一个真实的可以点击操作的3D场景。
别担心,我们不需要重新创建BP_Camera。基于我们之前创建摄像机的方式,BP_Camera可以被多次拖拽到场景中,只需进行少量修改,就可以轻松实现一个布置了多个活动摄像机的场景。