面向软件工程师的统一基本概念

2020-10-12 21:45:16

如果你正试图以软件工程师的身份进入游戏开发领域,寻找具有合适背景水平的学习材料可能是一件具有挑战性的事情。您可能会面临以下两种选择:一种是在向您介绍基本C#和OOP概念的同时描述Unity概念的材料,另一种是从高级教程开始,然后由其演绎出核心概念。

为了填补这一空白,我正在撰写一个名为“软件工程师统一”的系列文章。这是第一篇,我将在接下来的几周里发布更多的分期付款,所以一定要订阅更新。这些系列是为那些已经熟悉编程和软件体系结构的人准备的,特别是那些像我一样学得最好的人:从最基本的原则开始,一路向上。

大约17年前,我选择了Game Maker,开始了我的编程之旅。花了无数个小时编写小游戏和工具让我对编程产生了更大的热情。最终,我的注意力主要集中在软件工程上。从我的同龄人那里,我知道这是我们中的许多人寻找编程的一条相当常见的道路。

然而,与那些日子相比,游戏开发场景已经发生了巨大的变化。当我在离开游戏开发很长一段时间后去接Unity时,我最感兴趣的是理解基本概念:游戏的基本构件是什么?关于这些构建块是如何在内存或磁盘上表示的,我需要了解哪些信息?惯用代码是如何组织的?首选的模式是什么?

在本系列的第一篇文章中,我们将重点讨论前两个问题。

场景是在内存中组织对象的最大单位。场景包含组成游戏的对象。

在基本使用中,一个场景表示游戏中的单个关卡,其中在任何给定点加载一个场景。在更“高级”的使用中,您一次可以有两个或更多活动场景。场景可以被添加和卸载1.在游戏过程中加载多个场景在构建一个巨大的世界时特别方便;将遥远的区域保存在磁盘上而不是内存中将帮助您保持在性能预算内。

游戏对象(代码中的GameObject)是游戏的基本构件之一。

游戏对象既可以表示您在游戏中看到的物理事物(例如,玩家、地面、树、地形、灯光、武器、子弹、爆炸),也可以表示形而上学的事物(例如,库存管理器、多玩家控制器等)。在你的游戏里。

每个游戏对象都有一个位置和旋转。对于形而上学的物体来说,这并不重要。

游戏对象可以相互嵌套。每个对象的位置和旋转都是相对于其父对象的。场景中的直接对象是相对于“世界空间”坐标的。

您可能出于多种原因选择嵌套对象。例如,您可能会认为将所有“环境”对象(例如,组成城市或村庄的各个部分)放在一个空的父对象下在组织上是有意义的。这样,它可以在场景视图中折叠,并在构建游戏时轻松地一起移动。

游戏对象嵌套也可以具有功能意义。例如,“汽车”可以是一个对象,其代码整体上控制汽车的速度和旋转。但是各个子对象可能代表四个轮子(它们将独立旋转)、车身、车窗等。移动父汽车对象将移动所有子对象,保持它们相对于父对象(以及彼此)的相对方向。例如,我们可能希望玩家与汽车的其他部分分开与门进行交互。

组件为要执行的游戏对象实现一组定义良好的行为。造就一个物体的一切都来自于组成它的组件:。

汽车的一个“可见”部分将有一个绘制它的渲染器组件,并且可能有一个设置其碰撞边界的碰撞器组件。

如果汽车表示玩家,则汽车对象本身可能有一个PlayerInput控制器,该控制器接受关键输入事件,并将这些事件转换为对汽车进行编码演示。

虽然您可以编写与对象1:1对应的大型复杂组件(例如,玩家组件对整个玩家进行编码,而敌人组件对敌人进行整体编码),但通常情况下,将您的逻辑分解成与单个特征相对应的流线型片段是很常见的。例如:

所有具有生命值的对象,无论是玩家还是敌人,都可能有一个LivingObject组件,该组件设置初始生命值、造成伤害并在死亡后触发死亡事件。

玩家可能另外有一个输入组件来控制它的移动,而敌人可能有一个AI组件来控制它的移动。

组件在其生命周期中接收各种回调,在Unity中称为消息。消息的示例包括OnEnable/OnDisable、Start、OnDestroy、Update等。如果对象实现Update()方法,则当对象处于活动状态且给定组件处于启用状态时,Unity将在Gameloop的每一帧中自动调用此方法。这些方法可以标记为私有;Unity引擎仍然会调用它们。

组件还可以如您预期的那样公开公共方法。其他组件可以引用组件并调用这些公共方法。

资源是构成游戏项目的磁盘资源。这些资源包括网格(模型)、纹理、精灵、声音和其他资源。

当序列化到磁盘时,您的场景被表示为由其中的游戏对象组成的资源。我们还将在下一节中讨论如何将经常重用的游戏对象制作成称为预置的资源。2个。

资产还可以表示不太有形的东西,如输入控制映射、图形设置、I18N字符串数据库等。您还可以使用ScriptableObjects创建您自己的自定义资产类型。我在这里写过这些是如何保存的。

对于正在开发的项目,资产与代码一起构成项目代码库的关键表示形式。

您的内置捆绑游戏将包含您的大部分资产。这些资产将保存在安装游戏的设备的磁盘上。

游戏对象、它们的组件和它们的输入参数作为单个实例存在于场景中。但是,如果某一特定类别的对象通常是重复的,该怎么办呢?这样的对象可以制成预制件,预制件实际上是资产形式的对象。

场景中预制件的实例可以具有区分它的局部修改(例如,如果树对象是预制件,则可以具有不同高度的树实例)。预制件的所有实例都继承并覆盖来自其预制件的数据。

具有预设子对象的父对象本身可以是预制件。在父预制中,子预制实例可以有其自己的修改。在场景中,整个预制层次被实例化,并且特定于场景的修改可以层叠在上面。

场景中具有自己的本地修改的预置实例可以另存为其自己的“预置变量”资源。变体是从另一个预制件继承的预制件资源,在顶部应用其他修改。

例如,这些概念由嵌套预制件的预制变体或预制变体的预制变体组成。

项目的资源、场景和对象都保存在磁盘上。在编辑游戏时,这些对象被加载到内存中,并使用Unity的序列化系统保存回磁盘。在玩测试游戏时,内存中的对象和场景通过相同的序列化系统加载。该系统还可以在编译包中的资源和内存中加载/卸载的场景对象之间进行映射。

Unity Engine的序列化/反序列化流程将磁盘上的资源加载到内存中(在您的项目中:用于编辑/播放测试;在游戏中,当加载场景时),并负责将已编辑对象和组件的状态保存回其场景和预制结构中。

因此,序列化系统也是Unity EditoreExperience本身的核心。要使MonoBehavior在场景中实例化时接受构造输入,必须序列化这些字段。

大多数核心的Unity类型,如游戏对象、单一行为和资产资源都是可串行化的,并且可以在Unity编辑器中接收创建时的初始值。默认情况下,MonoBehavior上的公共字段是序列化的(如果它们是可序列化的类型),私有字段也需要用Unity的[SerializeField]属性标记才能序列化。

这六个概念涵盖了在Unity中构建游戏的基本结构部分。了解更多关于这些的知识,以及磁盘上的资源如何映射到内存中表示,应该会让您获得遵循一些更高级教程所需的直觉。

了解编辑器并将您的软件工程最佳实践映射到游戏开发最佳实践将有助于磨练您的技能。更重要的是,了解照明、动画控制器、导航网格、输入处理等广泛领域也会对您有很大帮助。

我将在本系列的后续迭代中介绍其中的许多主题,但我希望您掌握的知识可以使您的游戏开发之旅变得更加直观。

不过,一次只能有一个“主要”活动场景。↩。

“资产”这个词有点过载了。场景是预制的,像其他资源一样在您的项目中序列化和组织。您可以在Asset视图中与代码和其他资产一起浏览这些内容。如果你深入到编辑器中去操控一项资产,那么预制件和场景通常不能被当作资产来处理。↩

您可以通过网络加载一些资产或使用其他资产管理技术来进一步优化您的游戏。↩。

您也可以订阅并保持在循环中-这将意味着很多!