玩家角色:第 1 部分

Tutorial

Beginner

+0XP

30 mins

Unity Technologies

玩家角色:第 1 部分

在上一教程中,您探索了 Unity Editor 并导入了该项目的资源。现在,您可以开始处理玩家角色了!

在本教程中,您将:

  • 创建一个预制件来表示玩家角色
  • 开始为角色设置动画
  • 确保角色对物理设置有反应

在本教程结束时,您将能够编写第一个脚本来控制 John Lemon 的动作。

Languages available:

1. 保存场景

在上一教程中,您探索了 Unity Editor 的布局。还发现场景是由游戏对象组成的,这些对象包含一些组件可用于指定游戏对象在游戏中的工作方式。

现在是时候将游戏对象添加到您自己的场景中了!

创建新项目时,Unity 会自动创建一个名为“Untitled”的空场景。


选择 File > Save 或按 Ctrl/Cmd + S,然后选择要保存文件的位置。目前已经有一个名为 Scenes 的文件夹,因此我们在该文件夹中将该场景保存为“MainScene”。

您将在 Project 窗口中看到此时会创建一个名为 MainScene 的场景资源。


现在您有一个可以使用的场景了。在本教程的剩余部分中,我们将使用此场景。请记住要经常按 Ctrl/Cmd + S 来保存更改!

2. 添加角色模型

在上一教程中,您导入了制作此游戏所需的所有资源。您将使用的第一个资源是一个 3D 模型

在 3D 游戏中看到的大多数都是模型,包括角色、环境和道具。这些通常是在 Unity 外部创建的,然后将它们导入并赋予相应的功能以制作游戏。为了使用这些模型,需要将它们添加为游戏对象(这称为创建模型的实例)。

让我们添加玩家角色 John Lemon:

1.在 Project 窗口中,选择 Assets > Models > Characters 文件夹,然后找到名为 JohnLemon 的模型。

2.将模型从 Project 窗口拖入 Scene 视图。在此过程中可以精确选择要放置模型的位置。(还可以将模型拖到 Hierarchy 中以在默认位置创建游戏对象。)

3.将鼠标悬停在 Scene 视图上,然后按 F 进行聚焦。

现在,您应该可以在场景中看到玩家的角色!还可以在 Inspector 中找到有关刚刚实例化的游戏对象的信息。当前,该游戏对象具有两个组件:

  • 一个 Transform 组件,这意味着该游戏对象在场景中具有位置和大小

一个 Animator 组件,这意味着该游戏对象可以动画化

但是,除了这些功能之外,此角色还有更多需要考虑;例如,您需要能够在 Scene 视图中看到玩家角色,但这些组件均不能解决这个问题。

4.Hierarchy 窗口中,找到 JohnLemon 游戏对象。

该游戏对象的名称旁边有一个箭头,这表示游戏对象有子项。

5.单击箭头以展开 JohnLemon 并查看其子项。

此游戏对象有两个子项:一个名称也是 JohnLemon 的游戏对象,还有一个名为 Root 的游戏对象。选择名为 JohnLemon 的子游戏对象。

此游戏对象包含一个名为 Skinned Mesh Renderer(带蒙皮的网格渲染器)的组件。正是这个组件可让您看到角色。

模型由一个包含三角形的网格组成,该网格由 Mesh Renderer(网格渲染器)进行“渲染”,从而使该网格可见。Skinned Mesh Renderer 是一种特殊类型的 Mesh Renderer,可让网格根据模型所有骨骼的位置和旋转来改变形状。这些骨骼是模型的子游戏对象 — JohnLemon 的骨骼是 Root 游戏对象的所有子项

6.在 Hierarchy 中,选择 Root 游戏对象。按住 Alt (Windows) 或 Option (macOS) 并单击该游戏对象的名称左侧的箭头以展开其所有子游戏对象。

每个游戏对象都代表 JohnLemon 身体的一部分。

7.单击工具栏中的 Play 按钮以进入播放模式。

8.在 Hierarchy 中,选择名为 LeftForeArm 的游戏对象。在其 Transform 组件中,找到 Rotation 字段,并将 Y 值设置为 90

在 Scene 视图中,应该会看到 JohnLemon 的左臂弯曲了 90 度。JohnLemon 在本质上形成动画的方式如下:角色父游戏对象上的 Animator 组件将改变所有骨骼游戏对象 Transform 组件的旋转,这些改变将一起发生以形成角色的动画。

9.再次按 Play 按钮退出播放模式。请注意,退出播放模式时,在播放模式下所做的任何更改都不会保存。

10.通过按住 Alt (Windows) 或 Option (macOS) 并单击 JohnLemon 父游戏对象旁边的箭头,再次折叠所有游戏对象。

在深入探讨角色创建方法之前,让我们先了解一下预制件以及它们如何帮助您创建游戏。

3. 什么是预制件?

预制件是一种特殊类型的资源,代表已设置组件的一个游戏对象或一组游戏对象。预制件就像一个蓝图,可用于轻松创建同一对象的实例。预制件的每个实例都关联到预制件资源,因此更改这个资源将更改所有场景中的所有预制件版本。

在项目中,这种机制的第一个用途是让角色成为预制件。这意味着,如果您继续为游戏制作多个关卡,则无需为每个关卡重新制作 JohnLemon,只需实例化一个新的预制件即可。

预制件可以在 Hierarchy 窗口中通过其蓝色名称和图标加以识别:

但是等一下!JohnLemon 游戏对象有一个蓝色的名称和一个蓝色的立方体图标,但是立方体上有一张小白纸。JohnLemon 游戏对象已经是预制件了吗?

差不多接近了:在 Unity 中,模型的工作方式与只读预制件类似。它们是用于为该模型创建实例的蓝图,但是蓝图本身无法更改。

4. 将角色转化为预制件

您需要能够在此预制件上进行更改,所以让我们制作一个可以调整的新预制件:

1.将游戏对象从 Hierarchy 中拖入 Project 窗口中的 Assets > Prefabs 文件夹。随后会出现一个对话框,询问是要创建原始预制件 (Original Prefab) 还是预制件变体 (Prefab Variant),请选择 Original Prefab


以此方式拖动游戏对象会使其成为预制件(不管将其拖动到哪个文件夹中)。为了使项目保持井然有序,将所有预制件保存在 Prefabs 文件夹中会很有帮助。

2.现在已经创建了 JohnLemon 预制件,对该预制件所做的任何更改都将反映在场景中的 JohnLemon 预制件实例上。为了更改预制件,需要打开预制件以在预制件模式下进行编辑。在执行该操作之前,请按 Ctrl + S (Windows) 或 Cmd + S (macOS) 保存场景。

现在您可以打开 JohnLemon 预制件!

3.在 Inspector 窗口中,单击 Open Prefab 按钮。


Unity Editor 现在处于预制件模式下。此模式让您退出先前正在编辑的场景,进入仅包含预制件的临时场景。Scene 视图略有变化:顶部有一个新栏位在左侧显示 Scenes | JohnLemon,右侧有一个“Auto Save”复选框。

Scenes | JohnLemon 是当前正在预制件模式下编辑的预制件的导航路径。在本示例中,正在编辑的只有 JohnLemon 预制件,从此处返回将回到先前正在编辑的场景。

4.禁用 Auto Save 复选框(启用此复选框会降低速度)。这种情况下将出现一个 Save 按钮,可以手动保存对预制件所做的任何更改。

5.Hierarchy 窗口也在顶部有一个新的栏位。


左侧有一个箭头可以沿导航路径返回。如果您现在单击箭头,它将带您回到 MainScene。

在这里的整个 3D Beginner 项目中,您将编辑预制件,而且大多数情况下,您将进入预制件模式来进行此操作。习惯于在场景中编辑游戏对象与编辑预制件之间切换是使用 Unity 的核心操作。

现在,您可以对 JohnLemon 预制件进行首次更改,使该预制件产生动画。

5. 动画化您的角色

您的玩家角色将在此游戏中具有两段不同的动画:一段是玩家移动时的行走动画,另一段是不移动时的空闲动画。

选择 JohnLemon 游戏对象,然后在 Inspector 中查看其 Animator 组件。第一个属性称为 Controller。它引用了一种称为 Animator Controller 的资源类型,您将使用这种资源来移动 JohnLemon。

Animator Controller 有一个状态机用于确定 Animator 组件在任何给定时间应该为其层级视图设置的动画。该动画基于事先在 Animator Controller 上设置的动画剪辑。

6. 创建 Animator Controller

首先,让我们创建一个 Animator Controller:

1.在 Project 窗口中,找到 Assets > Animation > Animators 文件夹。右键单击该文件夹,然后选择 Create > Animator Controller

2.将 Animator Controller 命名为“JohnLemon”,然后双击它以便在 Animator 窗口中对它进行编辑。

Animator 窗口有两个主要部分:

  • 左侧有一个面板用于编辑 Animator 层 (Layers) 和 Animator 参数 (Parameters)
  • 右侧有一个区域显示状态机本身

3.单击 Animator 窗口左上角的 Parameters 选项卡。

Animator Controller 的状态机根据其 Animator 参数的当前值进行决策。这些 Animator 参数具有由脚本设置的值。每个独立变量都需要一个参数以用于影响角色正在播放的动画。

JohnLemon 将具有两段动画:一段是不移动时的空闲动画玩家,另一段是移动时的行走动画。因此该角色可能处于两种状态:行走或不行走。

有四种参数:

  • 一个 float 参数,该参数具有浮点变量值(带小数位的数字)。
  • 一个 int 参数,该参数具有整数值(不带小数位的数字)。
  • 一个 bool 参数,该参数具有布尔值(可以是 true 或 false)。
  • 一个 trigger 参数,这是一种特殊的参数,不包含任何值 — 这会导致从一段动画切换到另一段动画。

在本示例中,角色要么正在行走,要么处于静止状态,因此使用 bool 参数最适合。

4.单击 + 按钮,然后从下拉菜单中选择 Bool 来创建新的 Bool Animator 参数。

5.将新的 Animator 参数命名为“IsWalking”。正确拼写和区分大小写很重要;在下一教程中,当您编写第一个脚本时,您会了解原因。

IsWalking 参数名称的右侧有一个禁用复选框。

这是该参数的默认值。如果没有玩家输入,您的角色将保持静止,因此 IsWalking 应该为 false。这意味着您无需在此处进行任何更改。

7. 设置动画

现在,您可以确定要播放的动画,但是还没有准备好的动画,所以我们需要设置一些动画。

1.在 Project 窗口中,打开 Assets > Animation > Animation 窗口。

目前,动画具有显示其外观的图标。但是,在本示例中,如果可以在列表视图中查看资源,将更加方便。在 Project 窗口的右下角找到滑动条,并将其一直拖动到最左侧。

2.您应该会看到五个模型,其中两个以 John@ 开头。该命名约定可让您知道这些是 JohnLemon 的动画。

展开 John@IdleJohn@Walk,以便可以看到它们的子资源。

这些子资源显示父游戏对象的直接子项(记住,模型被实例化为游戏对象)、网格和动画。对于这些模型,动画分别为 Idle 和 Walk。

3.为了在 Animator Controller 中使用这些动画,请将它们从 Project 窗口拖到 Animator 窗口。先从 Idle 开始。

4.动画存在于包含 Animator 状态的 Animator Controller 中。在您拖入 Idle 和 Walk 动画时,Animator Controller 创建了两个包含这些动画的状态,并以动画命名。

Animator 状态是 Animator Controller 包含的状态机的一部分。状态机包含判定哪个状态为当前状态的逻辑。当前状态随后确定正在播放的动画。

默认状态显示为橙色。在本示例中,默认状态为 Idle,因为您首先拖入的就是这个状态。通过右键单击某个状态并选择 Set As Layer Default State,可以更改默认状态。

现在,您的状态机中有两个状态,但是没有逻辑用于定义应播放的状态。当前,状态机将以默认状态启动,并且永远不会改变,因此 JohnLemon 将始终处于空闲状态。为了添加一些逻辑,需要创建 Animator 过渡

8. 创建 Animator 过渡

要创建 Animator 过渡,请执行以下操作:

1. 右键单击 Idle 状态,然后选择 Make Transition。此时将开始一段跟随鼠标光标的过渡。

要完成过渡创建,请单击 Walk 状态。

2.您的角色需要能够从行走中恢复为空闲状态,因此请重复此过程以创建从 Walk 到 Idle 的过渡。

状态机应如下所示:

3.状态机现在可以在两段动画之间进行过渡,但是尚不知道何时进行过渡。还记得创建的 IsWalking 参数吗?此参数用来确定状态机应当切换动画还是保持不变。

通过单击连接线选择从 Idle 到 Walk 的过渡。

4.在 Inspector 中,查看该过渡的设置。第一项需要更改的设置是 Has Exit Time 复选框

如果 Has Exit Time 为 true(启用此复选框),则在经过一定时间后,将自动进行过渡,并且状态机将播放下一个状态。在此游戏中,控制过渡的时间很重要,因此请禁用 Has Exit Time 复选框。

在 Inspector 窗口的更下方,现在将显示一条警告消息:“Transition needs at least one condition or an Exit Time to be valid, otherwise it will be ignored”。由于您刚刚禁用了 Has Exit Time 复选框,因此目前没有理由进行此过渡。您需要添加一个条件以提供过渡。

9. 向过渡添加条件

要向过渡添加条件,请执行以下操作:

1. 单击 Conditions 列表(当前为空)下的 + 按钮。

2.角色行走时(即 IsWalkingtrue 时)需要从 Idle 到 Walk 的过渡。

创建的默认条件实际上就是您在这里需要的:如果 IsWalking 为 true,则 JohnLemon 应该从 Idle 过渡到 Walk。您无需进行任何更改!

接下来,需要设置从 Walk 到 Idle 的过渡。此过渡具有类似的要求。

3.在 Animator 窗口中选择从 Walk 到 Idle 的过渡。禁用 Has Exit Time 复选框 — 和以前一样,您不希望在一定时间后改变状态,而只是在您希望改变时才改变。

4.现在,Has Exit Time 复选框已禁用,您需要创建另一个条件。

此条件还应该选中 IsWalking,但是这次应将值设置为 false。如果角色未处于行走状态,则应该从 Walk 过渡到 Idle。

Animator Controller 现已完成!

10. 将 Animator Controller 分配给 JohnLemon 预制件

您仍然需要告诉 JohnLemon 预制件这是它应该使用的 Animator Controller:

1.在 Project 窗口中,选择 Assets > Animation > Animators,然后找到 JohnLemon Animator Controller。

2.在 Hierarchy 中选择 JohnLemon 游戏对象,然后将 Animator Controller 拖动到 Inspector 中 Animator 组件的 Controller 属性。这是非常重要的一步;没有它,JohnLemon 将无法移动。

3.单击 Scene 窗口右上角的 Save 按钮(可能需要选择 Scene 选项卡才能执行此操作)。

现在,JohnLemon 预制件的每个实例都已更新以包含您所做的更改。

11. 使角色对物理产生反应

您的角色将在有不同房间和走廊的鬼屋中游历探索。由于他不是幽灵,因此请务必确保他不能穿透墙壁!

为此,您需要确保 JohnLemon 预制件对物理产生反应:

1.打开 JohnLemon 预制件以便在预制件模式下进行编辑。在 Inspector 中,您将找到两个组件:Transform 和 Animator。为了对物理产生反应,您的角色还需要两个组件:Rigidbody 和 Collider。

Rigidbody 组件将游戏对象标记为可移动的物理系统的一部分。由于您肯定希望角色能够移动并且我们希望其撞到墙壁(因此成为物理系统的一部分),因此 JohnLemon 游戏对象需要一个 Rigidbody 组件。


2.单击 Add Component 按钮。

3.在出现的搜索栏中,键入“Rigidbody”,然后从出现的选项中选择它。

这是一个 3D 项目,因此请确保单击 Rigidbody 而不是 Rigidbody 2D。如果不小心添加了某个组件,可以使用组件上下文菜单(组件右上角的齿轮)将其删除。

4.保存到目前为止在 JohnLemon 预制件上所做的工作,确保不会丢失任何内容。

5.现在,您已经为 JohnLemon 预制件提供了一个 Rigidbody 组件,因此该预制件将对重力等物理效应做出反应。让我们进入播放模式并查看实际效果。通过单击 Scene 视图顶部的 Scenes 返回 MainScene,然后按工具栏上的 Play 按钮。

嗯,结果不太对:角色跌落一小段距离后停了下来。请再次按 Play 按钮退出播放模式。

这是由 Animator 引起的。Animator 组件上的第三个属性是 Apply Root Motion,该属性当前已启用。

12. 什么是根运动 (Root Motion)?

动画用于在特定层级视图中移动和旋转所有游戏对象。这些移动和旋转大多数都是相对于其父项完成的,但是层级视图的父游戏对象没有父项,因此它们的移动不是相对的。此父游戏对象也可以称为根 (Root),因此其移动称为根运动 (Root Motion)。

重要注意事项!在 JohnLemon 预制件的层级视图中称为根的游戏对象指的是其骨架的根,而不是实际的根游戏对象。根游戏对象是 Animator 组件所在的任何游戏对象,在本例中,该游戏对象称为 JohnLemon。

在 Animator 组件上启用了 Apply Root Motion,因此根在动画中的任何移动都将应用于每一帧。由于 Animator 正在播放 Idle 动画,没有移动,因此 Animator 不会施加任何动作。那么,为什么 JohnLemon 游戏对象会移动呢?这是因为 Animator 的更新模式 (Update Mode)

13. 什么是更新循环?

游戏的工作方式与电影和电视类似:一幅图像显示在屏幕上,该图像每秒变化多次,给人以运动的感觉。我们称这些图像为;将这些帧绘制到屏幕上的过程称为渲染。对于电影和电视,通常会预先定义要在屏幕上显示的下一幅图像,但是在游戏中,下一幅图像可能会发生巨大变化,因为用户会对接下来发生的事情产生影响。每幅图像都需要根据用户输入进行计算 — 由于这种变化可能在转瞬间发生,因此计算显示内容的程序要以同样快的速度进行运算。这称为更新循环

每次显示帧时,都会依序发生许多事情。您现在只需要知道,自定义组件的 Update 方法被调用后,会在屏幕上渲染新图像。这些更新的长度会有所不同,具体取决于计算和渲染的复杂程度。但是,还有另一个单独的循环可以运行所有物理操作。此循环不会改变更新的频率,因此称为 FixedUpdate

Animator 组件可以更改其执行更新的时间。默认情况下根据渲染执行此更新。这意味着 Animator 在 Update 中移动角色,而 Rigidbody 同时在 Fixed Update 中移动角色。这就是造成您的问题的原因,很容易解决!

14. 修复 John Lemon 的移动问题

首先让我们返回编辑预制件:

1.在 Inspector 窗口中,单击 Prefab Open 按钮。

2.找到 Animator 组件。在 Update Mode 属性下拉选单中,选择 Animate Physics

此更改将使 Animator 通过物理适时移动角色。现在,在移动角色的更新循环之间应该没有竞争,并且角色将对物理设置产生应有的反应。

3.您已经看到动画没有任何垂直的根运动,但这不会阻止 JohnLemon 与某些对象碰撞后发生垂直移动。有几种方法可以阻止这种情况。

最明显的选择是禁用 Rigidbody 组件上的 Use Gravity:

这样可以防止角色跌落,但这并不是您想要的。禁用 Use Gravity 的情况下,如果碰撞将角色下推,则该角色仍可能跌落;如果碰撞将角色上推,则该角色会漂走。您肯定不希望发生这种情况,因此您需要使用物理来限制角色的移动

4.找到 RigidBody 组件,然后单击箭头以展开 Constraints 属性。

这些 Constraint 属性会限制刚体 (Rigidbody) 的移动方向。

让我们探索一下 Unity 的坐标系,以准确了解其工作原理。

15. Unity 中的坐标

Unity 中的位置和方向采用 x、y 和 z(它们一起构成一个矢量)表示的 3D 坐标。在下一教程中,您将发现有关矢量的更多信息。一个场景具有这些方向的全局定义,在 Scene 窗口的右上方可以看到。

彩色箭头表示每个轴的正方向,而相反的灰色箭头表示负方向:

  • x 轴为红色
  • y 轴为绿色
  • z 轴为蓝色

16. 位置和旋转

场景中没有父项的游戏对象都具有相对于场景原点 (0, 0, 0) 的位置。有父项的游戏对象都具有相对于其父项的位置。但是,由于游戏对象可以旋转,因此子项的相对(或本地)位置将位于其父项经过旋转的坐标中。刚体约束 (Rigidbody Constraints) 引用的正是这些本地坐标(或轴)。

让我们看一下 JohnLemon 游戏对象的本地轴:

1.选择 JohnLemon 游戏对象,然后查看 Scene 视图。

您将看到:

  • x 轴(红色)指向角色的右侧
  • y 轴(绿色)指向上方
  • z 轴(蓝色)指向前方


2.那么您的角色应该有什么约束?

您的角色需要能够向前和左右移动,因此无需约束其 x 或 z 位置。但是,重要的是不能上下移动。要阻止这种移动方式,请启用 Freeze Position Y 复选框

3.旋转是指围绕特定轴的旋转。例如,如果角色绕其 x 轴旋转,则看起来角色处于正面或背面躺下的状态:

如果角色绕其 z 轴旋转,则看起来角色处于侧面躺下的状态:

JohnLemon 不应以上述任何一种方式移动,因此请启用 Freeze Rotation X 和 Z 复选框。JohnLemon 需要转身,因此请保持 Freeze Rotation Y 复选框处于启用状态。

现在 Rigidbody 组件已设置完成,您的角色将对物理系统做出反应。但是,该角色在场景中实际上还没有任何实体存在 — 没有任何对象可以碰到角色,角色也不能碰到其他任何对象。为了使角色在场景中保持实体存在,它需要一个碰撞体 (Collider)

17. 向 John Lemon 添加碰撞体

碰撞体是一个通用术语,涵盖了许多不同的组件。碰撞体定义了用于物理碰撞的对象的形状,使角色能够碰撞其他对象以及被碰撞。Collider 组件具有许多不同的形状,但是最适合 JohnLemon 的最简单形状是胶囊碰撞体 (Capsule Collider)

1.单击 Inspector 窗口中的 Add Component 按钮并搜索 Capsule Collider。选择 Capsule Collider 选项,确保不要单击 Capsule Collider 2D。

2.目前,Capsule Collider 并未真正将模型覆盖,因此游戏中的碰撞无法正常进行 — 您需要调整 Capsule Collider 的大小和位置,以使其近似于 JohnLemon 的形状。

将 Capsule Collider 的 Height 属性更改为 1.4,并将 Center 属性更改为 (0, 0.7, 0)。

这些更改意味着碰撞体的中部离地面只有其高度的一半,由于 JohnLemon 高约 1.4 米,因此该形状可以很好地覆盖他。


3.不过仍然有点宽 — 请将 Capsule Collider 的 Radius 属性更改为 0.4

该胶囊现在看起来具有正确的形状!

现在,您的角色可以对物理做出所需的反应,即可以撞到墙壁但是跌落。

18. 总结

在本教程中,您已经开始处理游戏角色。您初步了解了预制件的功能,并创建了一组简单的规则来约束 JohnLemon 的行为。在下一教程中,您将通过编写第一个脚本来探索角色拼图的最后一部分!

Complete this Tutorial