- Unity教程
- 统一 - 主页
- Unity - 简介
- Unity - 安装和设置
- Unity - 创建精灵
- Unity - 修改精灵
- 变换和对象父子关系
- Unity - 内部资产
- Unity - 保存和加载场景
- Unity - 基本运动脚本
- Unity - 理解碰撞
- Unity - 刚体和物理
- Unity - 自定义碰撞边界
- 了解预制件和实例化
- Unity - 游戏对象销毁
- Unity - 协程
- Unity - 控制台
- Unity - 音频简介
- Unity - 从 UI 开始
- Unity - 按钮
- Unity - 文本元素
- Unity - 滑块
- Unity - 材质和着色器
- Unity - 粒子系统
- Unity - 使用资源商店
- Unity 有用资源
- Unity - 快速指南
- Unity - 有用的资源
- 团结-讨论
Unity - 快速指南
Unity - 简介
Unity是一款跨平台游戏引擎,最初由Unity Technologies于2005年发布。Unity的重点在于2D和3D游戏以及互动内容的开发。Unity现在支持超过20种不同的目标平台进行部署,其中最受欢迎的平台是PC、Android和iOS系统。
Unity 具有用于设计和构建游戏的完整工具包,包括图形、音频和关卡构建工具的界面,只需很少使用外部程序即可处理项目。
在这个系列中,我们将 -
- 学习如何使用 Unity 的各种基础知识
- 了解引擎中的一切工作原理
- 了解游戏设计的基本概念
- 创建和构建实际的示例游戏
- 学习如何将您的项目部署到市场
现在让我们开始吧。
Unity - 安装和设置
要使用Unity创建内容,主要要求是下载Unity引擎和开发环境。除了核心引擎之外,您还可以下载用于部署到各种不同平台的可选模块,以及用于将 Unity 脚本集成到 Visual Studio 中的工具。
要安装 Unity,请转到此处,然后单击 -
选择您的 Unity + 下载。
在下一页上,单击“个人”下方的“立即尝试”按钮。这是 Unity 的免费版本,包含所有核心功能。当我们开始本系列时,最好在考虑购买Plus或Pro之前先了解如何使用该引擎。
在下一页上,向下滚动并单击以确认您或您的公司的年收入不超过 100,000 美元。如果这样做,您将无法尝试 Unity Free,但您可以注册 Pro 版本的 30 天免费试用版。
接下来,单击您想要安装 Unity 的平台。在本系列中,我们将讨论该引擎的Windows版本。也可以在Ubuntu和其他一些 Linux 系统上安装 Unity,请参阅此处了解更多信息
强烈建议您安装最新版本的Visual Studio ,它通过Unity附带的标准 MonoDevelop IDE 提供了许多有用的工具。
下载安装程序后,请浏览它,直到出现一个菜单,用于选择您希望使用 Unity 安装的组件。
在这里,选择您需要的组件。对于本系列,我们要安装您在图像中看到的组件。此选择包括引擎本身、引擎文档、IDE;适用于 Android 的构建工具以及您稍后可以添加到项目中的资产集合。
单击“下一步”,按照说明和选项进行操作,然后让 Unity 下载并安装到您的计算机上。
打开 Unity,在下一课中我们将创建我们的第一个项目。
创建您的第一个项目
Unity 同样适合 2D 和 3D 游戏。在 Unity 中制作的所有游戏都从启动屏幕开始作为项目。
打开新安装的 Unity 副本;将出现如下所示的屏幕 -
您现有的项目将显示在模糊区域中,如上图所示。
在窗口的右上角,您将看到“新建”图标,如上所示。单击该图标后,您将看到“项目设置”屏幕。
在这里,您可以为项目命名、设置保存位置、设置项目类型并添加现有资源。
现在,让我们将第一个项目命名为“Hello World!” 并将其设置为2D模式。
单击“创建项目”并让 Unity 设置项目的核心文件。这可能需要一些时间,具体取决于您的计算机速度、预添加的资产和项目类型。
了解发动机
创建新项目并打开 Unity 后,将出现以下屏幕 -
让我们快速浏览一下该窗口中可见的内容。目前,我们关注四个主要区域 -
这个窗口是我们构建场景的地方。场景是游戏中所有事情发生的关卡。如果单击小“游戏”选项卡,您可以看到一个预览窗口,显示游戏对玩家的外观。目前,它应该是一个简单的蓝色背景。
这个区域就是督察。现在它是空的,因为我们的场景中没有任何对象。稍后我们会看到 Inspector 是如何使用的。
这个窗口就是场景层次结构。它列出了当前打开的场景中的所有对象及其父子层次结构。我们很快就会将对象添加到此列表中。
最后,该区域是“项目资源”窗口。您当前项目中的所有资源都存储并保存在此处。所有外部导入的资源(例如纹理、字体和声音文件)在用于场景之前也都保存在这里。
在下一课中,我们将讨论 Unity 中游戏的工作流程和工作方式。
Unity如何运作?
在 Unity 中,所有游戏玩法都发生在场景中。场景是游戏各个方面(例如游戏关卡、标题屏幕、菜单和过场动画)发生的关卡。
默认情况下,Unity 中的新场景将在场景中拥有一个称为Main Camera 的Camera对象。可以向场景添加多个摄像机,但我们现在只处理主摄像机。
主摄像头在称为视口的特定区域中渲染它看到或“捕获”的所有内容。进入该区域的所有东西对玩家来说都是可见的。
通过将鼠标放在场景视图内并向下滚动以缩小场景视图,您可以看到此视口为灰色矩形。(您也可以通过按住 Alt 并拖动鼠标右键来执行此操作)。
场景本身是由称为GameObjects 的对象组成的。游戏对象可以是任何东西,从玩家的模型到屏幕上的 GUI,从按钮和敌人到看不见的“管理器”(如声源)。
游戏对象有一组附加的组件,这些组件描述了它们在场景中的Behave方式,以及它们对场景中其他对象的反应方式。
事实上,我们现在就可以探索这个问题。单击场景层次结构中的主摄像机并查看检查器。现在它不会是空的;相反,它将包含一系列“模块”。
对于任何游戏对象来说,最重要的组件是其变换组件。场景中存在的任何对象都将具有一个变换,它定义其相对于游戏世界或其父级(如果有)的位置、旋转和缩放。
通过单击“添加组件”并选择所需的组件,可以将其他组件附加到对象。在后续课程中,我们还将向游戏对象附加脚本,以便为它们提供编程Behave。
现在让我们考虑一些组件的示例 -
渲染器- 负责渲染并使对象可见。
Collider - 定义对象的物理碰撞边界。
Rigidbody - 赋予对象实时物理属性,例如重量和重力。
音频源- 提供播放和存储声音的对象属性。
音频监听器- 实际“听到”音频并将其输出到播放器扬声器的组件。默认情况下,主相机中有一个。
Animator - 允许对象访问动画系统。
光- 使对象充当光源,具有各种不同的效果。
在此图表中,我们可以看到 Unity 如何通过 GameObject 将自身组合成场景。
在下一课中,我们将创建第一个游戏对象并深入研究脚本编写。
Unity - 创建精灵
精灵是简单的 2D 对象,上面有图形图像(称为纹理)。当引擎处于 2D 模式时,Unity 默认使用精灵。在 3D 空间中查看时,精灵看起来像纸一样薄,因为它们没有 Z 宽度。
除非在 3D 空间中旋转,否则精灵始终以垂直角度面向相机。
每当 Unity 制作新的精灵时,它都会使用纹理。然后将该纹理应用到新的 GameObject 上,并将Sprite Renderer组件附加到其上。这使得我们的游戏对象通过纹理可见,并赋予它与它在屏幕上的外观相关的属性。
要在 Unity 中创建精灵,我们必须为引擎提供纹理。
让我们首先创建纹理。获取要使用的标准图像文件(例如 PNG 或 JPG),保存它,然后将图像拖到Unity 的资源区域中。
接下来,将图像从Assets拖到Scene Hierarchy中。您会注意到,一旦松开鼠标按钮,带有纹理名称的新游戏对象就会出现在列表中。您现在还将在场景视图的屏幕中间看到该图像。
让我们在创建精灵时考虑以下几点 -
通过从外部源拖入 Unity,我们添加了一个Asset。
这个资源是一个图像,所以它变成了一个纹理。
通过将此纹理拖到场景层次结构中,我们将创建一个与纹理同名的新游戏对象,并附加一个精灵渲染器。
该精灵渲染器使用该纹理来绘制游戏中的图像。
现在我们已经在场景中创建了一个精灵。
在下一课中,我们将研究我们拥有的精灵的一些修改器。
Unity - 修改精灵
我们刚刚导入的精灵还可以通过各种方式进行操作来改变它的外观。
如果您查看引擎界面的左上角,您会发现一个工具栏,如下所示 -
让我们讨论一下这些按钮的功能。
手形工具用于在场景中移动而不影响任何对象。
接下来,我们有移动工具。这用于移动游戏世界中的对象。
在中心,我们有旋转工具,用于沿游戏世界(或父对象)的 Z 轴旋转对象。
缩放工具位于上方。此工具可让您沿特定轴修改对象的大小(比例)。
最后,我们有矩形工具。此工具的Behave类似于“移动”和“缩放”工具的组合,但很容易损失准确性。它在排列 UI 元素时更有用。
随着项目复杂性的增加,这些工具被证明是有价值的。
Unity - 变换和对象父子关系
当我们刚开始时,我们讨论了游戏对象的变换如何可以说是其最重要的组成部分。让我们在本章中详细讨论该组件。此外,我们还将了解Object Parenting的概念。
变换具有三个可见属性 -位置、旋转和缩放。其中每一个都具有三个轴的三个值。2D 游戏在定位时通常不关注 Z 轴。Z 轴在 2D 游戏中最常见的用途是创建视差。
旋转属性定义对象相对于游戏世界或父对象绕该轴旋转的旋转量(以度为单位)。
对象的比例定义了它与其原始大小或原始大小相比有多大。例如,我们取一个尺寸为 2x2 的正方形。如果这个正方形相对于 X 轴缩放 3,Y 轴缩放 2,我们将得到一个大小为 6x4 的正方形。
在后续部分中,我们将讨论什么是对象育儿。
什么是对象育儿?
在 Unity 中,对象遵循层次结构系统。使用这个系统,游戏对象可以成为其他游戏对象的“父母”。
当游戏对象有父对象时,它将针对另一个游戏对象而不是游戏世界执行所有变换更改。
例如,没有父对象放置在 (10, 0, 0) 的对象将距离游戏世界中心 10 个单位。
但是,父级位于(10, 0, 0) 的游戏对象将认为父级的当前位置为中心。
只需将游戏对象拖放到所需的父对象上即可为其设置父对象。“子”对象在对象列表中显示为带有一个小缩进以及父对象旁边的箭头。
建立游戏对象的父子关系有多种用途。例如,坦克的所有不同部分都可以是单独的游戏对象,其父级位于名为“tank”的单个游戏对象下。这样,当这个“坦克”父游戏对象移动时,所有部件都会随之移动,因为它们的位置会根据其父游戏对象不断更新。
在接下来的课程中,我们将讨论内部资产。我们还将学习如何创建和管理项目中的资产。
Unity - 内部资产
除了从其他程序导入的外部资源(例如音频文件、图像、3D 模型等)之外,Unity 还提供内部资源的创建。这些资源是在 Unity 本身内创建的,因此不需要任何外部程序来创建或修改。
内部资产的一些重要示例如下所示 -
场景- 这些充当“级别”。
动画- 这些包含游戏对象动画的数据。
材质- 这些定义了光照如何影响对象的外观。
脚本- 将为游戏对象编写的代码。
预制件- 这些充当游戏对象的“蓝图”,因此可以在运行时生成它们。
其他一些重要的资产是占位符、精灵和模型。当您需要快速占位符时可以使用这些占位符,以便稍后可以用适当的图形和模型替换它们。
要创建内部资产,请右键单击资产文件夹并转到创建。
在此示例中,我们将创建一个三角形和一个正方形。
滚动精灵选择并单击三角形。
对Square重复此过程,您应该有两个新的图形资源。
随着我们的进展,我们将探索更多这些内部资产,因为它们对于构建合适的游戏至关重要。
Unity - 保存和加载场景
一天结束时,当您完成相当多的工作时,您希望保存进度。在 Unity 中,按 Ctrl + S 不会直接保存您的项目。
Unity 中的一切都发生在场景中。保存和加载也是如此;您必须将当前工作保存为资产中的场景(.unity 扩展名)。
让我们尝试一下。如果我们按 Ctrl + S 并给场景命名,我们将在资产区域中看到一个新资产。这是场景文件。
现在,让我们尝试创建一个新场景。为此,右键单击资源并转到“创建”→“场景”。为您的新场景命名并按 Enter 键。
在编辑器模式下(当游戏未运行时),可以通过双击场景将其加载到编辑器中。加载当前场景中未保存更改的场景将提示您保存或放弃更改。
你的第一个脚本
导入图像并让它们在游戏中保持静止并不会真正给你带来任何好处。也许它可以成为一个漂亮的相框,但不是一个游戏。
脚本对于在 Unity 中制作游戏至关重要。脚本编写是编写代码块的过程,这些代码块像组件一样附加到场景中的游戏对象。脚本是您可以使用的最强大的工具之一,它可以成就或毁掉一款优秀的游戏。
Unity 中的脚本编写是通过 C# 或 Unity 的 JavaScript 实现(称为 UnityScript)完成的(但是,随着 2018 年周期,UnityScript 现在开始弃用阶段,因此建议不要使用它)。出于本系列的目的,我们将使用 C#。
要创建新脚本,请右键单击您的资源并转到“创建”→“C# 脚本”。您还可以使用引擎顶部栏中的“资产”选项卡。
当您创建新脚本时,应该会显示一个新资产。暂时保留该名称不变,然后双击它。您的默认 IDE 应与脚本一起打开。让我们看看它到底是什么。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { // Use this for initialization void Start() { } // Update is called once per frame void Update() { } }
您将看到您的脚本名称是从MonoBehaviour派生的类。什么是单一Behave?它是一个巨大的类和方法库。它帮助 Unity 中的所有脚本以一种或另一种方式派生。在 Unity 中编写脚本越多,您就越会意识到 MonoBehaviour 实际上是多么有用。
当我们继续进行时,我们有两个没有任何返回类型的私有脚本,即Start和Update方法。Start方法在场景中使用该方法的游戏对象处于活动状态的第一帧运行一次。
Update方法在 Start 方法之后运行游戏的每一帧。通常,Unity 中的游戏以 60 FPS 或每秒帧数运行,这意味着当对象处于活动状态时,Update方法每秒被调用 60 次。
Unity 脚本允许您利用整个 MonoBehaviour 类以及核心 C# 功能,例如泛型集合、lambda 表达式和 XML 解析等。在下一课中,我们将编写我们的第一个代码!
Unity - 基本运动脚本
在本课中,我们将编写代码,使游戏对象根据用户的输入向上、向下、向左和向右移动。这应该可以帮助我们更轻松地理解 Unity 脚本编写的工作流程。
请记住,每个 GameObject 至少有一个组件 - Transform。特殊之处在于游戏对象的变换也在 Unity 的脚本端显示为变量,因此我们可以通过代码对其进行修改。这也不限于 Transform;Unity 中的所有组件都有属性,可以通过脚本中的变量访问这些属性。
让我们从我们的运动脚本开始。创建一个新脚本,并将其命名为“Movement”。
现在,打开脚本,您应该会看到与上一课中看到的内容相同的内容。
让我们创建一个名为speed的公共浮点变量。在 Unity 中公开变量有很大的优势 -
该变量在编辑器中显示为可修改字段,因此您不必手动调整代码中的值。
public class Movement : MonoBehaviour { public float speed; }
如果我们保存这个脚本而不触及其他方法,它应该在 Unity 中编译。
(您可以通过右下角的图标看到它何时编译。)
接下来,将脚本从资源拖放到游戏对象上。如果你做得正确,这就是你应该在游戏对象的属性中看到的内容 -
由于速度值是可调的并且不需要一直在代码中更改,因此我们可以使用 update() 方法而不是 start() 。
现在让我们考虑 Update 方法的目标 -
检查用户输入。
如果有用户输入,请阅读输入说明。
根据对象的速度和方向更改其变换的位置值。为此,我们将添加以下代码 -
void Update() { float h = Input.GetAxisRaw(“Horizontal”); float v = Input.GetAxisRaw(“Vertical”); gameObject.transform.position = new Vector2 (transform.position.x + (h * speed), transform.position.y + (v * speed));
现在让我们讨论一下 breif 中的代码。
首先,我们创建一个名为h (水平)的浮点变量,其值由Input.GetAxisRaw方法给出。此方法返回 -1、0 或 1,具体取决于玩家在上/下/左/右箭头上按下的键。
Input 类负责以按键、鼠标输入、控制器输入等形式从用户获取输入。GetAxisRaw 方法稍微难以理解,因此我们稍后再讨论。
接下来,我们将游戏对象的位置更新为通过创建新的Vector2定义的新位置。Vector2 有 2 个参数,分别是它的x 和 y值。对于 x 值,我们提供对象当前位置及其速度的总和,在按键按下到其位置的每一帧中有效地添加一些量。
保存此脚本并返回 Unity。一旦编译成功,Unity 将自动更新所有脚本,因此您不必一次又一次地重新附加脚本。
现在您已完成,将GameObject 属性中的速度值更改为 0.8。这很重要,因为较高的值会让玩家移动得太快。
现在,单击“开始”并查看您的第一个小游戏的运行情况!
尝试按箭头键并四处移动。要停止游戏,只需再次按“播放”即可。您甚至可以实时调整速度,这样您就不必一直停止和启动它。
在下一课中,我们将学习刚体和碰撞。
Unity - 理解碰撞
Unity 中的碰撞与实际 Sprite 本身分离,作为单独的组件附加并自行计算。现在就让我们来了解一下这背后的原因吧。
游戏中的所有内容都是 GameObject。即使构成关卡的各个图块本身也是游戏对象。
当我们将每个组件视为一个游戏对象时,我们意识到场景中可能有数千个游戏对象,并以某种方式相互交互。您可以想象,如果 Unity 向每一个游戏对象添加碰撞,那么引擎为每一个游戏对象计算碰撞将是不切实际的。
我们将继续添加一个简单的“墙”,我们的玩家角色可以与它发生碰撞。为此,请创建另一个精灵并使用矩形工具将其放大。我们还将通过Sprite Renderer 组件中的Color属性为其指定红色。
现在,转到检查器中的“添加组件”,然后输入“Box Collider 2D”。单击显示的第一个组件,就会出现一个新组件。
您将在游戏对象的周边看到一条亮绿色的线。这就是碰撞边界。它定义了可碰撞对象的实际形状。
对我们的可移动游戏对象也重复相同的操作。
当然,Unity 中的碰撞不仅仅限于简单的盒子。它们可以有各种形状和大小,并且不一定是对象参数的复制品。
它们也可以呈现多边形形状。
开发人员和设计人员在碰撞边界中使用近似形状来简化碰撞器并避免引擎不必要的计算的情况并不罕见。我们很快就会学习如何使用碰撞器创建不同的形状和大小。
现在我们已经有了碰撞边界,点击播放并查看它的实际效果。
您会注意到我们的可移动对象表现不正常。我们将在后续章节中讨论该对象的Behave。
Unity - 刚体和物理
上一章中冲突的主要问题在于代码。我们现在将直接修改游戏对象位置的值。如果玩家按下某个键,我们只是向该位置添加一个值。我们需要一种方法让玩家移动时能够对边界和其他游戏对象做出正确的反应。
为此,我们需要了解什么是刚体。刚体是允许游戏对象对实时物理做出反应的组件。这包括对力和重力、质量、阻力和动量的反应。
您只需单击“添加组件”并在搜索字段中输入 Rigidbody2D,即可将 Rigidbody 添加到游戏对象。
单击 Rigidbody2D 会将组件附加到您的游戏对象。现在它已经附加了,您会发现许多新的领域已经打开。
在默认设置下,游戏对象将由于重力而垂直下落。为了避免这种情况,请将重力比例设置为 0。
现在,玩游戏不会显示任何明显的差异,因为游戏对象与其物理组件没有任何关系。
为了解决我们的问题,让我们再次打开代码并重写它。
public class Movement : MonoBehaviour { public float speed; public Rigidbody2D body; // Update is called once per frame void Update() { float h = Input.GetAxisRaw(“Horizontal”); float v = Input.GetAxisRaw(“Vertical”); body.velocity = new Vector2(h * speed, v * speed); } }
我们可以看到,我们在声明中创建了对 Rigidbody2D 的引用,并且我们的更新代码适用于该引用而不是对象的变换。这意味着刚体现在被赋予了移动的责任。
您可能期望主体引用抛出 NullReferenceException,因为我们没有为其分配任何内容。如果你按原样编译并运行游戏,你会在编辑器左下角看到以下错误
为了解决这个问题,让我们考虑一下脚本创建的组件。请记住,公共属性在 Unity 中创建自己的字段,就像我们对速度变量所做的那样。
将速度调整到更高的值,大约5,然后玩游戏。
您的碰撞现在可以正常工作了!
Unity - 自定义碰撞边界
在本章中,让我们了解自定义碰撞边界。我们还将学习如何调整碰撞器的大小和形状。
让我们从 Box Collider 开始。盒子碰撞器 (2D) 有 4 个可调节的边,形状像矩形。在碰撞器的组件中,单击此框 -
您将看到对撞机上出现 4 个“手柄”。您可以拖动这些手柄来调整它们的大小。
对于简单的形状,Unity 也会检测最适合碰撞体形状的形状,前提是您选择了正确的形状。例如,在圆形精灵上选取圆形碰撞器将使其与其半径相匹配。
对于更复杂的形状,Unity 将尝试创建最简单但最复杂的碰撞器形状。为此,您需要使用Polygon Collider 2D。
尝试单击“编辑碰撞器”按钮并尝试调整碰撞器。
了解预制件和实例化
在游戏过程中实例化和销毁对象被认为非常重要。实例化仅仅意味着实现。物品在游戏中出现或“生成”,敌人死亡,GUI 元素消失,场景在游戏中始终加载。知道如何正确地摆脱不需要的物品以及如何将不需要的物品带入变得更加重要。
我们先来了解一下什么是预制件。预制件对于理解 Unity 中实例化的工作原理非常重要。
预制件就像游戏对象的蓝图。在某种程度上,预制件是游戏对象的副本,可以将其复制并放入场景中,即使在制作场景时它并不存在;换句话说,预制件可用于动态生成 GameObjects。
要创建预制件,您只需将所需的 GameObject 从场景层次结构拖到项目Assets中即可。
现在,为了实例化 GameObject,我们在脚本中调用Instantiate()方法。此方法在MonoBehaviour中定义,接受 GameObject 作为参数,因此它知道要创建/复制哪个 GameObject。它还具有用于更改新实例化对象的变换以及父子关系的各种覆盖。
让我们尝试在按下空格键时实例化一个新的六边形。
创建一个名为Instantiator的新脚本并将其打开。在Update方法中,输入下面给出的代码。
在这里,我们使用Input类的GetKeyDown方法来检查玩家在最后一帧中是否按下了特定按钮。由于我们希望它继续检查,因此我们将其放入Update中,每秒运行 60 次。如果在该帧中按下了KeyCode枚举(列出了标准键盘上所有可能的键)指定的键,则GetKeyDown 方法返回true 。
public class Instantiator : MonoBehaviour { public GameObject Hexagon; // Update is called once per frame void Update () { if (Input.GetKeyDown(KeyCode.Space)) { Instantiate(Hexagon); } } }
顶部的公共 GameObject 声明创建了一个插槽,类似于我们在上一课中为 Rigidbody2D 制作的插槽。但是,此插槽仅接受预制件(在编辑器时间)和游戏对象(在运行时)。
保存脚本并让它编译。完成后,通过转到对象层次结构右键菜单并选择Create Empty来创建一个新的空游戏对象。
将此对象命名为可识别的名称,例如Instatiator Object,并将我们新创建的脚本附加到它。在为游戏对象显示的插槽中,拖动我们创建的预制件。
如果我们现在运行游戏,按空格键将创建一个新的六角形对象,该对象与我们用于创建预制件的对象相同。您可以看到在对象层次结构中创建的每个六边形。你看不到它们出现在游戏中的原因是因为目前它们都是一个一个地创建的。
在下一课中,我们将了解对象销毁的概念。
Unity - 游戏对象销毁
游戏对象的销毁与实例化一样重要。在本章中,我们将学习如何销毁游戏对象。
幸运的是,销毁游戏对象和创建游戏对象一样容易。您只需要一个对要销毁的对象的引用,并以此引用作为参数调用Destroy()方法。
现在,让我们尝试制作 5 个六边形,当按下指定的键时它们会自行破坏。
让我们创建一个名为HexagonDestroyer的新脚本并在 Visual Studio 中打开它。我们将从创建一个公共KeyCode变量开始。KeyCode 用于指定标准键盘上的键,Input 类在其方法中使用它。通过公开此变量,就像我们之前对 Rigidbody 和 Prefab 所做的那样,我们可以通过编辑器访问它。当变量公开时,我们不需要将“KeyCode.A”等值硬编码到代码中。代码可以灵活地使用我们想要的任意数量的对象。
public class HexagonDestroyer : MonoBehaviour { public KeyCode keyToDestroy; // Update is called once per frame void Update () { if (Input.GetKeyDown(keyToDestroy)) { Destroy (gameObject); } } }
观察我们如何在方法中使用名为“gameObject”的变量(小号 g,大号 O)。这个新的gameObject变量(类型为GameObject)用于引用此脚本所附加的游戏对象。如果将此脚本附加到多个对象上,则每当涉及此变量时,它们都会以相同的方式做出反应。
但是,不要混淆两者。
带有大写 G 和 O 的GameObject是包含所有 GameObject 的类,并提供标准方法(例如 Instantiate、Destroy 和获取组件的方法)。
带有小g 和大写 O 的gameObject是GameObject 的特定实例,用于引用此脚本当前附加的游戏对象。
现在让我们编译代码,然后返回 Unity。
现在,我们将创建一个新的六边形精灵,并将脚本附加到它上面。接下来,右键单击层次结构中的游戏对象并选择“复制”。在层次结构中创建一个新的精灵;您应该使用移动工具重新定位它。重复这些步骤以创建类似的六边形。
单击每个六边形并查看它们的脚本组件。您现在可以设置各个键,以便游戏对象在按下该键时自行销毁。例如,让我们创建 5 个六边形,并设置它们在按下 A、S、D、F 和 G 键时销毁。
你可以在多个六边形上设置同一个按键,当按键按下时,它们都会同时自我毁灭;这是使用gameObject引用的示例,您可以使用脚本来引用各个对象,而无需单独设置它们。
可以在多个六边形上设置同一个按键,按下按键时它们都会同时自我毁灭;这是使用gameObject引用的示例,您可以使用脚本来引用各个对象,而无需单独设置它们。
重要的是要理解,销毁游戏对象并不意味着对象会破碎或爆炸。就游戏(及其代码)而言,销毁一个物体将简单地(并立即)停止其存在。该对象及其引用的链接现在已损坏,尝试访问或使用其中任何一个通常会导致错误和崩溃。
Unity - 协程
在 Unity 中制作游戏时,协程是最有用的工具。让我们考虑下面显示的代码行来了解协程的全部内容。
IEnumerator MyCoroutineMethod() { // Your code here… yield return null; }
一般来说,如果您在 Unity(或 C#,实际上)中调用函数,该函数将从头运行到结束。就您的代码而言,这就是您认为的“正常”Behave。然而,有时我们想要故意减慢某个函数的速度,或者让它等待的时间超过它运行的瞬间持续时间。协程正是能够做到这一点:协程是一个能够等待和计时其进程以及完全暂停它的函数。
让我们考虑一个例子来理解协程是如何工作的。假设我们想要制作一个正方形,它的颜色以 1 秒的间隔在红色和蓝色之间变化。
首先,我们创建一个精灵。接下来,创建一个新脚本,并将其命名为ColorChanger。在此脚本中,我们获得对精灵的精灵渲染器的引用。但是,我们将使用不同的方式来获取组件。我们将要求代码检测组件本身,而不是像我们到目前为止所做的那样将组件拖放到插槽中。
这是通过GetComponent方法完成的,该方法返回它检测到的第一个匹配组件。由于我们每个对象只使用一个 Sprite 渲染器,因此我们可以使用此方法每次自动检测并获取对渲染器的引用。
请记住,渲染器负责使精灵在屏幕上实际可见。渲染器有一个颜色属性,影响精灵的全局颜色;这是要修改的值。公开颜色值将使我们可以通过操作系统默认颜色选择程序中的编辑器来选择它们。
private SpriteRenderer sr; public Color color1; public Color color2; void Start () { sr = GetComponent<SpriteRenderer>(); StartCoroutine(ChangeColor()); } IEnumerator ChangeColor() { while (true) { if (sr.color == color1) sr.color = color2; else sr.color = color1; yield return new WaitForSeconds(3); } }
现在,我们将协程函数捕获在 while 循环中。
要在 C# 中创建协程,我们只需创建一个返回IEnumerator的方法。它还需要一个yield return语句。Yield return 语句比较特殊;它实际上告诉 Unity 暂停脚本并继续下一帧。
有多种方法可以用来产生回报;其中之一是创建WaitForSeconds类的实例。这使得协程在继续之前等待一定的现实世界秒数。
让我们编译代码并返回 Unity。我们只需选择交替颜色,然后点击播放即可。我们的对象现在应该以 3 秒的间隔在两种颜色之间切换。您可以将间隔设为公共变量,并调整颜色变化的频率。
协程广泛用于定时方法,就像我们刚才所做的那样。各种WaitForX方法都有各自的用途。协程还用于运行“侧面”进程,这些进程在游戏同时运行时自行运行。例如,当玩家从某一点开始时,这对于加载大关卡的屏幕外部分很有用。
Unity - 控制台
控制台是我们读取开发人员输出的地方。这些输出可用于快速测试代码位,而无需提供额外的测试功能。
默认控制台中显示三种类型的消息。这些消息可能与大多数编译器标准相关 -
- 错误
- 警告
- 留言
错误
错误是会阻止代码运行的问题或异常。
警告
警告是不会阻止代码运行的问题,但可能会在运行时引起问题。
留言
消息是向用户传达某些内容的输出;他们通常不会突出问题。
我们甚至可以让控制台输出我们自己的消息、警告和错误。为此,我们将使用 Debug 类。Debug类是 MonoBehaviour 的一部分,它为我们提供了将消息写入控制台的方法,与在入门程序中创建正常输出消息的方式非常相似。
您可以在资产区域上方带标签的选项卡中找到控制台。
控制台的输出对程序员更有用,而不是对最终用户或玩家更有用。
让我们尝试向控制台写入一条简单的消息。当按下空格键时,这会通知我们。为此,我们将使用Log方法,该方法接受一个对象作为参数,我们将在其中使用一个字符串。
您可以从新脚本开始或修改现有脚本。
void Update() { if (Input.GetKeyDown(KeyCode.Space)) Debug.Log(“Space key was pressed!”); }
保存、编译并运行此代码(当然,通过将其附加到游戏对象),尝试按空格键。
注意- 观察该消息显示在编辑器的底部。
如果单击“控制台”选项卡,您将发现打印出您的消息。
同样,您还可以使用LogWarning方法输出警告,并使用LogError方法输出错误。事实证明,这些对于测试少量代码非常有用,而无需实际实现它们,正如您稍后将看到的。
Unity - 音频简介
游戏强调音频是有原因的。为游戏增加审美价值是相当重要的。从第一个乒乓球开始,人们就可以听到球交替撞击球拍时发出的嘟嘟声和噼啪声。当时这只是一个非常简单的短方波样本,但您还想从所有视频游戏的鼻祖那里得到什么呢?
在现实生活中,许多因素都会影响您感知声音的方式;物体的速度、它所处的场景类型以及它来自哪个方向。
有许多因素可能会给我们的发动机带来不必要的负载。相反,我们尝试创建一个关于我们的声音如何在游戏中发挥作用的想法,并围绕它进行构建。这在需要处理 3 个轴的 3D 游戏中尤为突出。
在 Unity 中,我们拥有用于音频感知和播放的专用组件。这些组件协同工作,创建了一个可信的声音系统,让游戏感觉自然。
Unity 为我们提供了一系列有用的工具和效果,例如混响、多普勒效果、实时混音和效果等。我们将在后续章节中了解这些。
音频组件
在本节中,我们将了解 Unity 中与音频相关的 3 个主要组件。
音频源
AudioSource 组件是您将附加到游戏对象以使其播放声音的主要组件。当通过混音器、代码或默认情况下唤醒时触发时,它将播放AudioClip 。
AudioClip 只是加载到 AudioSource 中的声音文件。它可以是任何标准音频文件,例如.mp3、.wav 等。AudioClip 本身也是一个组件。
音频监听器
AudioListener 是监听场景中播放的所有音频并将其传输到计算机扬声器的组件。它的作用就像游戏的耳朵。您听到的所有音频都是从该 AudioListener 的位置角度来看的。场景中只能有一个 AudioListener 才能正常运行。默认情况下,主摄像机已附加监听器。监听器没有设计者想要关心的任何公开属性。
音频滤波器
AudioSource 的输出或 AudioListener 的接收可以在音频过滤器的帮助下进行修改。这些是可以改变混响、合唱、过滤等的特定组件。每个特定的过滤器都有自己的组件,并带有公开的值来调整它的声音。
播放声音
让我们尝试制作一个在单击时播放声音的按钮。首先,我们将创建一个圆形精灵,并将其设为红色。
现在,让我们将音频源附加到该精灵上。
为了让对象发出声音,我们必须给它一个声音。让我们使用这个声音效果来达到我们的目的。
http://www.orangefreesounds.com/ding-sfx/
下载音效,并将其拖到资产中。
当 Unity 将此资源作为声音文件导入时,它会自动转换为AudioClip。因此,您可以将此声音剪辑从资源中直接拖到精灵音频源中的音频剪辑插槽中。
将声音剪辑从资源直接拖到精灵音频源中的音频剪辑插槽后,请记住在音频源属性中取消选择“唤醒时播放”;如果不这样做,游戏开始时就会播放声音。
现在,让我们开始讨论我们的代码。创建一个名为“BellSound”的新脚本并将其打开。
由于我们的音频源是通过代码控制的,因此我们希望首先获得对它的引用。我们将像以前一样使用 GetComponent 方法。
public class BellSound : MonoBehaviour { AudioSource mySource; // Use this for initialization void Start () { mySource = GetComponent<AudioSource>(); }
现在,让我们设置检测被单击对象的方法。MonoBehaviour 为我们提供了所需的方法,名为 OnMouseDown。每当鼠标在该游戏对象的碰撞器范围内单击时,就会调用该方法。
由于我们还没有将碰撞器附加到按钮上,所以现在就这样做。
我们不需要一个刚体(Rigidbody);我们也不需要通过代码访问这个碰撞器。它必须存在才能使该方法发挥作用。
让我们测试一下该方法,看看它是否有效。在脚本中编写以下代码,并将其附加到按钮。
void OnMouseDown() { Debug.Log(“Clicked!”); }
保存脚本并附加后,即可玩游戏。单击该按钮应在控制台中生成一条消息。
您现在距离播放声音仅一步之遥。现在您所要做的就是调用Audio Source 实例中的Play方法。
void OnMouseDown() { mySource.Play(); }
保存脚本并在游戏中运行它。单击按钮,您应该会听到声音!
注意- 考虑制作一个按钮,每次单击它时音调都会升高。使用mySource.pitch和一个计数器,看看你是否能算出来。)
Unity - 从 UI 开始
在本节中,我们将了解 Unity 中用户界面或 UI 元素的设计过程。这包括基本设置以及 Unity 附带的常见元素的概述。
在 Unity 中设计 UI 的工作流程与我们迄今为止经历的流程略有不同。对于初学者来说,UI 元素不是标准游戏对象,因此不能直接使用。UI元素的设计不同;如果设置不正确,在 4:3 分辨率下看起来正确的菜单按钮在 16:9 分辨率下可能会显得拉伸或扭曲。
Unity 中的 UI 元素不会直接放置到场景上。它们始终被放置为称为Canvas的特殊 GameObject 的子级。Canvas 就像场景中 UI 的“绘图表”,所有 UI 元素都将在其中渲染。在没有现有 Canvas 的情况下从“创建”上下文菜单创建 UI 元素将自动生成一个。
现在让我们看看 Canvas GameObject 以了解其他新组件 -
顶部的矩形变换似乎具有许多标准游戏对象的变换所没有的新属性。
这是因为,普通 GameObject 的 Transform 描述3D 空间中的假想点,而RectTransform则定义假想矩形。这意味着我们需要额外的属性来准确定义矩形的位置、大小以及方向。
我们可以看到矩形的一些标准属性,例如高度和宽度,以及两个称为Anchors的新属性。锚点是其他实体可以在画布中“锁定”的点。这意味着,如果 UI 元素(例如按钮)锚定到右侧的 Canvas,则调整 Canvas 的大小将确保 Button 始终位于Canvas 的相对右侧。
默认情况下,您将无法修改画布区域的形状,它将是场景周围相对巨大的矩形。
接下来是画布组件。这是主组件,包含几个有关如何绘制 UI 的通用选项。
我们看到的第一个选项是渲染模式。此属性定义用于将 Canvas 绘制到游戏视图上的方法。
我们在下拉列表中有三个选项。让我们在后续部分中了解这些选项。
屏幕空间 - 叠加
此模式是菜单、HUD 等最标准的模式。它将 UI 呈现在场景中的所有其他内容之上,准确无误地排列方式。当屏幕或游戏窗口大小发生变化时,它还能很好地缩放 UI。这是画布中的默认渲染模式。
屏幕空间 - 相机
屏幕空间 - 相机创建一个假想的投影平面,距相机一定距离,并将所有 UI 投影到其上。这意味着场景中 UI 的外观在很大程度上取决于相机使用的设置;这包括视角、视野等。
世界空间
在世界空间模式下,UI 元素的Behave就像放置在世界中的普通游戏对象一样。然而,它们与精灵类似,因此它们通常用作游戏世界的一部分,而不是供玩家使用,例如游戏中的监视器和显示器。由于这种性质,您可以在此模式下直接修改 Canvas RectTransform 的值。
Canvas Scaler是一组选项,可让您以更明确的方式调整 UI 元素的比例和外观;它允许您定义当屏幕大小发生变化时UI 元素如何调整自身大小。例如,UI 元素可以保持相同的大小,无论屏幕大小如何,比例也相同,或者它们可以根据参考分辨率进行缩放。
Graphics Raycaster 主要处理 UI 元素的光线投射(链接到光线投射的 Unity 文档),并确保用户启动的事件(例如单击和拖动)正常工作。
Unity - 按钮
在本章中,我们将学习如何将 UI 元素插入场景中并开始使用它们。
让我们从一个Button开始。要插入按钮,请在场景层次结构中右键单击,然后转到Create → UI → Button。如果您没有现有的 Canvas 和 EventSystem,Unity 会自动为您创建一个,并将按钮也放置在 Canvas 内。
请记住,在默认模式Overlay渲染模式下,Canvas 的大小与相机的大小无关。您可以通过单击“游戏”选项卡来测试这一点。
如果您播放该场景,您会注意到该按钮已经具有一些标准功能,例如检测鼠标何时悬停在其上以及按下时改变颜色。
按钮需要功能在 UI 中真正有用。可以通过其属性添加此功能。
让我们创建一个新脚本,并将其命名为ButtonBehaviour。
public class ButtonBehaviour : MonoBehaviour { int n; public void OnButtonPress(){ n++; Debug.Log("Button clicked " + n + " times."); } }
我们制作了一个简单的方法来记录我们点击按钮的次数。
注意- 此方法必须是公共的;否则按钮的功能不会注意到它。
让我们创建一个空的 GameObject 并将此脚本附加到它。我们这样做是因为按钮本身不会执行任何操作;它只调用其脚本中指定的方法。
现在,进入按钮的属性,找到OnClick()属性。
点击底部选项卡上的 + 图标,列表中应显示一个新条目。
此条目定义按下按钮所作用的对象,以及调用该对象脚本的哪个函数。由于按下按钮时使用了事件系统,您只需将多个功能添加到列表中即可触发它们。
将包含我们创建的ButtonManager脚本的空 GameObject 拖放到None(对象)插槽中。
导航“No Function”下拉列表,然后查找我们的OnButtonPress方法。(请记住,它可以命名为您想要的任何名称,OnButtonPress 只是一个标准化的命名约定。)您应该在 ButtonBehaviour部分中找到它。
如果你现在玩游戏,你可以测试按钮,当然,控制台会打印出你按下按钮的次数。
Unity - 文本元素
Unity 的内置文本 UI 对于学习者设计 UI 来说是一个很好的起点,即使它往往会被更强大、更高效的社区构建的资产所掩盖。
就我们的目的而言,普通的 Text 元素足以开始使用。
文本本身就是一个独特的 UI 元素,这主要是由于该元素的动态性。例如,将玩家当前的分数打印到屏幕上需要在显示之前将分数的数值转换为字符串,通常通过 .toString ()方法。
要插入文本 UI 元素,请转到场景层次结构,创建 → UI → 文本。
新的文本元素应该显示在您的画布区域中。如果我们看一下它的属性,我们会看到一些非常有用的选项。
然而,最重要的是文本字段。您可以在该字段中输入您希望文本框显示的内容,但我们希望更进一步。
要更改文本的字体,您必须首先将字体文件作为资源从计算机导入到 Unity 中。字体不需要主动附加到场景中的任何东西,并且可以直接从资源中引用。
Text 元素也可以通过脚本访问;这就是动态UI的重要性所在。
与上一章一样,输出按钮被按下的次数,而不是控制台;让我们实际将其打印在游戏屏幕上。为此,我们将打开上一课中的 ButtonBehaviour 脚本,并对其进行一些更改。
using UnityEngine; using UnityEngine.UI; public class ButtonBehaviour : MonoBehaviour { int n; public Text myText; public void OnButtonPress(){ n++; myText.text = "Button clicked " + n + " times."; } }
我们所做的第一个更改是添加新的命名空间引用。该引用用于使用 Unity 的 UI 组件,因此我们添加 using UnityEngine.UI行。
接下来,我们创建一个公共 Text 变量,我们可以将 Text UI 元素拖放到其中。
最后,我们使用myText.text访问此 UI 元素包含的实际文本。
如果保存脚本,我们现在将在 ButtonManager 中看到 Text UI 元素的新插槽。只需将包含该文本元素的游戏对象拖放到插槽中,然后点击“播放”按钮即可。
Unity - 滑块
在本章中,我们将了解本系列中的最后一个 UI 元素。滑块通常用于应在最大值和最小值对之间设置某个值的情况。最常见的用途之一是音量或屏幕亮度。
要创建滑块,请转到创建 → UI → 滑块。一个新的Slider元素应该出现在您的场景中。
如果您转到此滑块的属性,您会注意到一系列用于自定义它的选项。
让我们尝试用这个滑块制作一个音量滑块。为此,打开 ButtonBehaviour 脚本(您可以重命名 ButtonManager GameObject,因为它现在所做的不仅仅是管理按钮)并添加对 Slider 的引用。我们还将再次更改一下代码。
public class ButtonBehaviour : MonoBehaviour { int n; public Text myText; public Slider mySlider; void Update() { myText.text = "Current Volume: " + mySlider.value; } }
了解我们如何使用 Update 方法不断更新 myText.text 的值。
在滑块属性中,让我们选中“整数”框,并将最大值设置为 100。
我们将通过其属性设置文本的颜色以获得更明显的颜色。
让我们按照相同的步骤将滑块游戏对象拖到新插槽上,然后点击播放。
强烈建议您也探索和试验其他 UI 控件,看看哪些控件以何种方式工作。
在接下来的部分中,我们将了解光照、材质和着色器。
Unity - 材质和着色器
在本章中,我们将简要了解材质和着色器。为了更好地理解,我们将创建一个新的3D