在开始任何游戏项目之前,对想要制作的内容进行规划非常重要.有时候,我们刚开始时头脑里的想法是很不错的,但是当开始创建角色或环境时,事情往往会偏离最初的意图.游戏设计能让我们规划好下列各个方面.
以上并不是游戏设计的详尽清单,但可以作为编写游戏设计文档的七点.
如果用谷歌搜索游戏设计文档,你将得到大量的文本模板,格式规则以及内容指导等信息,这往往让新手望而却步.事实上,设计文档往往是为创建文档的公司或团队量身定制的,通常有如下三种类型:
本篇将要制作的游戏都十分简单,不需要使用游戏设计文档或技术设计文档;相反,使用单页文档即可维护项目目标以及相关的背景信息.
:::info
游戏设计文档的格式没有正确和错误之分,这是发挥个人创意的好地方.你可以添加能够激发灵感的图片,并设计一些有创意的格式来展现自己的愿景.
:::
这里整理了一份简单的文档,列出了Hero Born游戏原型的基础设定.在进一步学习之前,请先通读这份文档,想一想如何应用自己目前已经学过的编程概念.
:::tips
概念
游戏原型专注于潜行躲避敌人,并收集治疗物品,还包含一些第一人称射击方面的内容.
游戏玩法
主要机制围绕着利用视线类领先巡逻的敌人并收集所需物品.战斗包括向敌人发射子弹,这会触发受击反馈.
接口
使用WASD或方向键控制移动,使用鼠标控制相机.空格键用来发射子弹,物品的收集则需要利用对象间的碰撞.简单的UI界面用来显示收集的物品和剩余的弹药,还有标准的血条用来显示生命值.
艺术风格
为了快速且高效地进行开发,关卡和角色都是最基本的GameObject
图元.如有需要,后续可以替换为3D模型和环境地形.
:::
为游戏构建关卡时,始终应该从玩家的角度进行考虑.你想让玩家看到怎样的环境?如何让他们感受,交互并行走于环境之中.你实际上构建的是游戏所处的世界,一定要保持一致.
在Unity中,可以选择使用地形工具创建室外环境,使用基础形状或几何体创建室内环境,甚至可以从其他软件中导入3D模型并在场景中使用,例如Blender.对于Hero Born这款游戏,我们始终使用简单的类似于竞技场的室内环境.另外,角落里会有一些可供隐藏的掩体,这些都比较容易制作.
Unity提供了很好的有关地形工具的入门资料,详见 https://docs.unity3d.com/Manual/Script-Terrain.html .如果想好好地制作地形,Unity资源商店里还有一份十分优秀的免费资源可供参考,详见 https://assetstore.unity.com/packages/tools/terrain/terrain-toolkit-2017-8490 .
观察一下大家平常玩的游戏,你可能会好奇:如何在屏幕上创建这些如此逼真的模型和物体?幸运的是,Unity包含一组可以直接选择的用于基本图形的GameObject以方便快速地制作游戏原型.这些图形并不精致,分辨率也不高,但是对于初学者来说可以节约时间.
在Hierachy面板中选择 Create | 3D Obkect, 你将看到一系列选项,期中有一半可用来创建基本的图形或形状.

(1)在Hierarchy面板中选择 Create | 3D Object | Plane
(2)在Inspector面板中将 GameObject 重命名为 Ground, 然后修改x,y,z轴的Scale修为3

我们刚刚创建了一个Ground对象并增大了其尺寸,以便未来放置更多房间供角色行走.按照真实生活中的物理规则,这个Ground对象将作为3D物体的边界,这意味着其他物体不能直接下落穿过边界.关于Unity物理系统及其如何工作的更多信息,在后续讲解.
现在,场景中有了第一个物体,可以讨论3D空间的知识了.具体来说,就是有关物体的位置,旋转,缩放等操作在三维空间中是如何实现的.回想一下高中所学的几何知识,一张包含x轴和y轴的坐标系统图示应该会让你感到很熟悉.
Unity同时支持2D和3D游戏开发.如果制作的是2D游戏,那么现有的说明已经足够了.然而,当在Unity编辑器中处理3D空间时,还会涉及z轴.z轴映射了深度,从而赋予物体立体感.
刚开始接触这些可能会让人困惑,好在Unity提供了一些十分方便的视觉指示来帮你弄明白这一切.Scene视图的右上角有一个几何图标,其中的x,y,z轴分别被标记为红色,绿色和蓝色.当选中场景中的任何对象时,也会显示相应的坐标指示箭头.

上图中的几何图形会始终显示场景和物体的当前朝向.单击任意一条彩色轴,就会切换场景至所选轴的朝向.
观察Ground对象的Transform组件,可以看到,位置,旋转和缩放都是按照这3个轴来定义的.位置决定了对象处在场景中的何处,选装决定了角度,缩放决定了尺寸.

这引出一个很有趣的问题:位置,旋转,缩放的参考点或原点是在何处设置的?答案是:这取决于使用的相对空间时什么.在Unity中,要么是世界空间,要么是本地空间.
世界空间和本地空间适用于不同场景,后续我们再详细介绍.
现在的地面并不好看,可以使用材质来让关卡更生动一些.材质能够控制GameObject在场景中的渲染方式效果由材质的着色器决定.可以认为着色器负责将光照和纹理数据组合起来,进而展示材质看起来的样子.

如图所示,每个GameObject一开始都有默认材质与着色器,颜色被设置为标准的白色.
下面创建一个新的材质,用它将地面颜色从暗白色修改为深蓝色
(1)在Project面板中,创建一个新的文件夹并命名为Materials.
(2)在Materials文件夹中,使用Create | Material 创建材质并命名为 Ground_Mat
(3)单击Ground_Mat对象,将它放到Hierarchy面板中的Ground对象上

之前创建的材质现在已经成为项目资源的一部分.拖放Ground_Mat材质至Ground对象上即可改变地面颜色,你对Ground_Mat材质所做的任何修改都会反映到地面上

白盒是设计术语,指的是使用一些临时对象排布出构想的内容,然后在后续时间里再用做好的资源替换它们.具体应用到关卡的设计中,就是使用一些基本的GameObject来构建环境,使之达到我们想要的效果.这是开展工作的好起点,尤其是在游戏的原型制作阶段.
在Unity中进行处理之前,可以先画出关卡的基本布局和位置.这有助于引发一些想法,从而更快地布置环境.

即便画的不好,也不要慌张,重要的是将脑海里的想法表达出来,并在进入Unity之前解决所有设计问题.

对于对象控制工具栏中的不同工具,下面从左到右分别对这些工具进行讲解.
与场景中对象的导航和移动相关的更多信息可以通过网址 https://docs.unity3d.com/Manual/PositioningGameObjects.html 找到
场景中对象的平移和导航操作可以使用类似的工具来完成,尽管我们不是在Unity编辑器中操作:
这种场景导航方式通常被叫作"飞行模式",当需要聚焦或移动到特定物体或观点时,可以组合使用这些功能.
有时候,在场景中移动十分枯燥,但随着你不断练习,事情最终会变简单.要想了解更多的场景导航特性,可访问网址 https://docs.unity3d.com/Manual/SceneViewNavigation.html
下面利用基本的图形方块和工具栏,在关卡周围缩放并放置四堵墙,以限制竞技场的主要区域.

务必确保项目里的层级尽可能组织好,这十分重要.理想情况下,你可能希望把相关的游戏对象放置到父对象下.目前,场景里只有很少的对象,不会构成什么风险.但是,当项目变得复杂,场景中有成百上千个物体时,你将对此感到十分头疼.
在关卡中,一些对象可以组织一下.Unity允许创建空的游戏对象,从而让这件事变得很简单.空对象是放置相关对象的理想容器,因为空对象上没有附加任何组件,仅仅相当于外壳.
下面把地面和四面墙分到一起,放到常规的空对象下.
(1)在 Hierarchy 面板中, 使用 Create | Create Empty 创建一个空对象并命名为Environment.
(2)拖放地面和四面墙至Environment对象下,使它们成为子对象
(3)选择Environment对象,确保x,y,z都被设置为0.

Environment对象在项目中的层级中是父对象,竞技场中的对象是它的子对象.现在,我们可以使用箭头图标展开或折叠Environment对象,这样Hierarchy面板就不那么凌乱了.
预制体是Unity中最强大的工具之一,不仅在创建关卡时很有用,而且可用来编写脚本,使用起来十分方便.预制体可视为能够保存并复用的GameObject,其中可以包含任意的子对象,组件,c#脚本以及属性.一旦创建,预制体就像类的蓝图一样,场景中的每一个副本都是预制体的独立实例.结果就是,你对预制体所做的任何修改都会改变场景中的所有实例.
要在竞技场的四个角落放置四个同样的角楼,使用预制体是最合适的方式.可以按如下步骤创建预制体:
(1)在Hierarchy面板中使用 Create | Create Empty 创建一个空对象, 命名为 Barrier_01
(2)创建两个基础的Cube对象,缩放并摆成v形
(3)创建另两个Cube对象,将它们放到已有物体的一端
(4)在Project面板中创建一个新的文件夹,命名为Prefabs.然后把Barrier_01拖进去,Barrier_01就会成为预制体.

Barrier_01及其所有子对象现在成了预制体,这意味着可以从Prefabs文件夹中拖放Barrier_01预制体的副本到场景中或直接在场景中复制一份来用.Hierarcht编办中Barrier_01将变为蓝色以表示状态变了,同时Inspector面板中多了一行用于预制体的功能按钮.
角楼的中央有一块空白,因此作为玩家的掩体并不是很适合.下面更新Barrier_01预制体,添加另一个Cube对象并应用所做的更改.
(1)创建一个Cube对象,将它放置到角楼地基的交汇处.
(2)Inspector面板中的Perfab标签会变为黄色,表示场景中的预制体被修改了.Unity会将新的Cube对象标记为白色,从而表示他不是预制体的一部分.
(3)单击Apply按钮,保存修改并更新预制体.

Barrier_01预制体现在包含一个新的Cube对象,整个预制体应该又变回了蓝色.
我们已经有了可复用的障碍物,接下来创建关卡中剩下的物体以实现前面所示的草图效果
(1)复制三次Barrier_01预制体,将每个对象摆放到竞技场的不同角落
(2)创建一个空对象,命名为Raised_Platform
(3)创建一个Cube对象并进行缩放以符合平台的要求
(4)创建一个Plane对象并缩放为坡道,探后旋转放置,使之与平台和地面相连
(5)复制坡道,然后重复刚才的旋转放置步骤
(6)再次重复上述步骤两次,直到有四个坡道通往平台
将你从本章学到的内容整合到一起可能要花上一段时间,但这是值得的.
(1)创建一个Capsule对象,将其摆放至合适的位置并进行缩放.
(2)创建并附加一个新的材质到Capsule对象上.
(3)将Capsule对象做成预制体并重命名为Health_Pickup
Unity中的光照是一个范围极广的话题,光照分为两种:实时光照和预计算光照.这两种光照都会考虑物体的属性(如颜色),光的强度以及朝向场景的方向等,不同之处在于Unity对光照行为的计算方式.
实时光照会在每帧进行计算,任何通过光线路径的物体都会投射实时阴影,就像真实生活中的光源一样.然而,这种方法会显著降低游戏的性能,并且消耗会随着场景中光源数量的增加而以指数级增加.预计算光照则会将场景的光照信息存储到一张名为光照贴图 (light map)的纹理中,随后应用到场景中.预计算光照是静态的,可以节省计算性能,但是当物体进入场景中时,光照不会实时发生变化.
还有一种混合光照类型,叫做"预计算实时全局光照"(Precomputed Realtime Global Illumination),这种光照填补了实时光照和预计算光照之间的空白.
每个场景默认都会使用直射光(Direction Light)作为主光源,但你也可以像创建其他游戏对象一样在层级中创建光源.即使刚刚接触光源控制方面的知识,也无须担心.光源同样是Unity中的对象,可以按需进行摆放,缩放和旋转.

我们先了解一下实时光源对象以及它们各自的性能:
反射探头(Reflection Probe)和光照探头(Light Probe)超出了Hero Born游戏的需要. 如果感兴趣,可以在Unity文档中查看
Light组件的所有属性都可以进行配置,从而创建令人沉浸的环境,需要了解的最基础属性是Color,Mode和Intensity.这个三个属性分别决定了光照的颜色,模式(实时光照或预计算光照)和强度.

就像其他Unity组件一样,Light组件的这些属性也可以通过脚本进行访问.
在Unity中可以为对象制作动画,范围可从简单的旋转效果直到复杂的角色移动行为.所有动画都是通过Animation和Animator窗口控制的.
关于Animator窗口和Animation Controller 的更多信息,可以通过文档找到.
任何需要应用动画片段的游戏对象都需要Animator组件,而Animator组件需要附加有Animation Controller. 在创建新的动画片段时,如果项目中还没有控制器, Unity就会创建一个并将其保存到动画片段所在的位置,然后就可以通过控制器来管理动画片段了.
下面通过创建动画片段使 Health_Pickup预制体动起来
(1) 使用 Window | Animation | Animation 打开 Animation面板,然后将 Animation面板固定到Console面板的旁边
(2) 确保 Health_Pickup被选中,然后单击Animation面板中的Create按钮
(3)使用弹出的界面创建一个名为Animation的文件夹,将新建的动画片段命名为Pickup_Spin
因为项目中没有任何Animation Controller, 所以Unity在Animations文件夹中创建了一个名为Pickup_Spin的控制器.只要选中Health_Pickup对象,创建动画片段的同时,就会向预制体添加一个设置了Animator Controller的Animator组件

现在已经有动画片段了,在Animation窗口中,我们可以看见空白的时间轴.本质上,当修改Health_Pickup对象的z轴旋转值或其他可用于动画的属性时,时间轴会将这些改变记录为关键帧.然后Unity将这些关键帧整合在一起变为一段完整的动画,就像将电影胶卷上每个独立的画面一起播放就会形成运动的图像一样.

为了使Health_Pickup预制体每秒绕着z轴完整的旋转360°,可以仅设置三个关键帧,然后让Unity处理剩下的事情.
(1)单击Record按钮,开始编辑动画.
(2)将光标置于时间轴0:00处,保持Heath_Pickup的z轴旋转值为0
(3)将光标置于时间轴的0:30处,设置z轴旋转值为180
(4)将光标置于时间轴的1:00处,设置z轴旋转值为360
(5)单击Record按钮,结束动画的编辑
(6)单机Record按钮右侧的Play按钮,查看整个动画播放效果

现在,Health_Pickup对象每秒会绕着z轴按0°,180°,360°来旋转,从而实现了循环旋转的效果.如果现在开始游戏,那么上述动画会一直持续下去直到游戏停止.
除了为对象属性设置动画之外,Unity还可以使用动画曲线来控制动画随时间进行变化.到目前为止,Animation窗口一直处于Dopesheet模式,可以在Animation窗口的底部进行切换.单击Curves标签,你将在右侧看到一条带有一些点的动画曲线,这些点可以替代之前记录的关键帧.旋转动画应该是平滑的(表现为动画曲线是线性的),因此让一切保持原状即可.通过拖动或调整动画曲线上的点,可以在动画运行时加速,减速或者改变动画中的任何点.
尽管动画曲线能够处理好属性怎样随时间变化的问题,但我们还是需要一种方式来修正 Health_Pickup动画重复播放时产生的抖动.我们可以通过修改动画切线来实现目的,因为动画切线控制着一个关键帧是怎样与另一个关键帧融合的.在DopeSheet模式下,右击任何关键帧,将弹出如图所示的菜单

本教程不会深入探究动画曲线和动画切线,可以在文档中查看更多信息.
下面调整动画的第一个关键帧和最后一个关键帧的动画切线,使动画在重复播放时可以无缝融合
(1)在时间轴上右击第一个和最后一个关键帧的菱形图标,从弹出的菜单中选择Auto
(2)移动Main Camera到能够看见Health_Pickup对象的位置,单击Play按钮.
改变第一个和最后一个关键帧的动画切线为自动方式后,Unity将使它们之间的变换变得平滑,从而消除了动画循环中开始或结束时的抖动.
提示:我们还可以使用C#脚本操纵特定的属性,例如位置和旋转,从而为对象设置动画.
当需要制作侏儒爆炸或外星飞船的尾焰喷流这种动态效果时,使用Unity的粒子特效最合适不过.粒子系统(Particle System)会发射很多精灵图(Sprite)或网格(Mesh),这些就是所谓的粒子,它们共同构成了视觉效果.粒子的属性是可以配置的,例如粒子的颜色,在屏幕上持续的时间,向着某个方向运动的速度等.可以将粒子系统创建为独立的对象,也可以将多个粒子系统作为对象组合起来以得到更真实的效果.
提示:粒子特效极为复杂,几乎可以实现任何你能够想象到的效果.然而,为了制作能够以假乱真的粒子特效,需要进行大量的实践.作为起点,可以参考 https://docs.unity3d.com/Manual/ParticleSystemHowTo.html
为了将玩家的注意力吸引到场景中放置的可收集对象上,可以为Health_Pickup对象添加一种简单的粒子特效
(1)在Hierarchy面板中选择 Create | Effect | Particle System
(2)将粒子系统放置在Health_Pickup的中间位置.
(3)选中粒子系统并在Inspector面板中修改如下属性
(4)展开Emissions标签并将Rate over Time设置为5
(5)展开Shape标签并将Shape设置为Sphere

创建好的粒子系统会根据Inspector面板中的属性设置在每一帧渲染并发射粒子