Unity学习笔记-3

本文最后更新于:2023年11月17日 下午

组件

添加组件

我们可以为我们的 GameObject 添加各种各样的组件,只需要在 Hierarchy 中选中对应的 GameObject,再在 Inspector 窗口中点击 Add Component 即可。

也许是一些常用的组件

前排提醒:做的是 2D 游戏,可能不会涉及到 3D 游戏的常用组件。
Rigidbody 2D:刚体组件。可以用来设置重力,Gravity Scale设置的是重力的比例。默认重力为y = -9.81Constraints则是对GameObject设置一些坐标上的约束,比如为了防止人物“摔倒”,可以冻结 z 轴旋转。Mass则是质量,碰撞时质量更小的飞得更远(确信)。Collision Detection则是碰撞检测模式,它的两个选项分别是Discrete(间歇检测)和Continous(持续检测)。

如果要更改一般的配置,如自定义重力,就从项目设置(Project Settings)里边进行更改。例如更改重力的路径:Edit -> Project Settings… -> Physics 2D -> General Settings -> Gravity。

Xxx Collider 2D:碰撞体组件。Xxx代表碰撞体形状。有许多形状的碰撞体,例如:Box、Capsule、Circle 等。

如果是为瓦片地图设置碰撞体的话,就请使用Tilemap Collider 2D组件吧!为了防止每一片瓦片都独立进行碰撞检测,可以再添加一个Composite Collider 2D,然后将Tilemap Collider 2D组件中的Composite Operation设置为Merge
不过要注意的是添加Composite Collider 2D组件的话还会自动添加一个Rigidbody 2D组件,会给我们的瓦片地图附上重力,别忘记将它的Body Type设置为Static,以此来消除这个重力。

创建及配置新输入系统

代码文件可以放在 Assets -> Scripts 文件夹下。

如何使用全新的 Input System

Edit -> Project Settings -> Player -> Other Settings -> Active Input Handling,将其改为 Input System Package。
然后在 Window -> Package Manager 中将 Packages 指定为 Unity Registry,搜索 Input System,安装该包即可完成全新输入系统的引入。

在 Other Settings 中我们还可以更改一下 Api Compatibility Level,将其改为 .NET Framework,这样在写代码的时候就可以利用更多 C# 的特性了。

如何创建输入系统

我们可以把输入系统相关文件放在 Assets -> Settings -> Input System 文件夹下。

手动创建

点击 + 号,找到 Input Actions 选项,点击创建即可。创建完成后,双击打开新建的输入系统,可以看到左边是 Action Maps,中间是 Actions,最右其实是 Action Properties。其中 Action Maps 可以理解为,我们为一个界面来创建一个输入系统,比如在菜单的时候调用的是名为 Menu 的 Action Map,而在玩游戏的时候调用的是 Gameplay 的 Action Map。
选中一个 Action Map 后,就可以为其添加 Action 了,比如控制移动 Movement。选中一个 Action 后,最右边的面板显示的是该 Action 的 Properties,也就是属性。可以看到里面有一个 Action Type,教程中使用的是 Value,而Action Type 设置为 Value 的话又会多出一个 Control Type,如果要使用 W A S D 来控制方向的话,就将这个 Control Type 设置为 Vector 2。
此时,再点击选中的 Action 的右边的 + 号,就会发现里边多了一个 Add Up/Down/Left/Right Composite,这就是为 Action 添加上下左右组件选项啦。

自动创建

选择代表我们游戏人物的 GameObject,为其添加 Player Input 组件,再点击组件中的 Create Actions… 即可。

使用输入系统

第一种方式,在 Player Input 组件中,将 Behavior 修改为 Invoke Unity Events,然后在 Events 中对详细操作进行设置。
第二种方式,通过写代码的方式使用。选中我们刚刚创建的 PlayerInputControl,其中有一个 Generate C# Class 选项,勾选并点击 Apply,就会生成对应的 C# 类。接着回到人物 GameObject,双击 Player Controller,在里边编写我们的代码来调用输入系统。先实例化一个PlayerInputControl对象,然后调用PlayerInputControl.Gameplay.Move.ReadValue<TValue>方法来读取数值。

实现人物移动和翻转

一旦一个物体被挂载上了 Rigidbody 刚体组件,那么它的坐标就由这个刚体组件来驱动了。打开刚体组件中的 Info,里边的 Positon、Rotation 可以覆盖 Transform 中的 Positon 和 Rotation。

通过刚体组件实现移动

获取刚体组件

在 Player Controller 中添加一个字段Rigidbody2D rb,至于该字段的可访问性,分为两种情况进行选择。如果要在所有代码执行前对该字段进行一些设置的话,就选择public修饰符,使其在 Inspector 中可见,然后将 Rigidbody2D 组件直接拖拽到该字段上。如果不需要在游戏执行前就设置值的话,那就可以使用private修饰符,然后在Awake方法中对其进行初始化:rb = GetComponent<Rigidbody2D>()

如果要获取该 GameObject 上的某一个(T)组件的话,就使用GetComponent<T>方法吧!

修改刚体组件速度

如果要在游戏中更新我们 GameObject 的状态(比如更新一些字段的值),就可以使用UpdateFixedUpdate方法,前者是每一帧都会执行的方法,而后者则是以一个固定的时钟频率来执行,这使得后者在不同运算速度的设备上,能够获得一致的更新频率,所以,我们通常也将所有有关物理的方法放在这里面执行。
很明显,我们不希望在运算速度快的设备上人物跑得比在运算速度慢的设备上快,所以我们会在FixedUpdate中修改人物的速度。当然了,我们是通过调用方法的方式来对速度进行修改的,尽量不要直接在FixedUpdate方法中直接对字段进行修改。所以,我们创建一个Move方法,在该方法中修改速度,然后再在FixedUpdate中调用Move方法。
Move方法中,我们通过修改rb字段的velocity属性来修改速度。

将鼠标悬停在velocity属性上,可以看到其描述:Linear velocity of the Rigidbody in units per second. 即:刚体每秒的线速度。

velocity是一个Vector2类型的值,所有我们直接new一个Vector2对象,其构造函数接受两个参数,分别对应 x 轴上的值和 y 轴上的值。x 轴的数值应该修正为:当前输入(用于判断正负移动) 乘以 速度(基本速度值) 乘以 修正值(时间修正值),即:inputDirection * speed * Time.deltaTime。y 轴数值应该修正为rb.velocity.y,即维持原有的 y 轴上的线速度不变,因为原本 y 轴上就保持着一个重力的线速度。

如果是使用Transformpositon做加减去移动,则需要乘以Time.deltaTime去修正速度。但如果用的是Rigidbody2Dvelocity,速度只是一直在修正为同一个速度,不需要用Time.deltaTime去修正。

翻转人物

如果想要翻转我们的人物,可以直接改变 Transform 组件的 Scale 的值,也可以修改 Sprite Renderer 组件中的 Flip 来进行翻转(但是用 Flip 的话角色身上的组件并不会随着角色的翻转而翻转)。
在这里我们使用传统的修改 Transform 组件中 Scale 的值来进行翻转。大致的思路就是:用一个局部变量faceDir保存当前的transform.localScale.x的值,然后根据输入方向inputDirection.x来修改faceDir的值,最后根据这个最新的faceDir的值来修改transform.localScale的值即可。

人物跳跃

首先,为我们的跳跃绑定按键。打开之前创建的 InputController,在 Gameplay 的 Action Map 下创建新的名为 Jump 的 Action,Action Type 为 Button(为该动作绑定按键),为此 Action 添加一个空格键的 Binding。这一步是为了能在我们的代码中获得关于跳跃按键输入的事件,所以下一步就是来到我们的 PlayerController.cs 中编写代码。
代码逻辑是这样的:创建一个Jump方法,然后添加到按键按下这个事件(其实是Action委托)中去,即:inputControl.Gameplay.Jump.started += Jump;,这样每次检测到我们的跳跃键按下的时候都会执行一次Jump方法。
最后就是Jump方法的实现了。通过刚体(Rigidbody2D)组件的AddForce方法,我们可以为 GameObject 施加一个力。要进行跳跃,也就是施加一个向上的力,即:rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);。这行代码中,rb是当前 GameObject 的 Rigidbody2D 组件;transform则是当前 GameObject 的 Transform 组件,up是其属性;jumpForce是我们自定义的一个float类型的字段,代表要施加的跳跃力;ForceMode2D.Impulse则是说明施加的是瞬时力,这里还有另外一种ForceMode2D.Force,施加的是持续力。
至此可以说跳跃部分就完成了,剩下的就是运行游戏,调整jumpForceGravity Scale的值了(当然你也可以改Mass的值)。
但是,这里仍然存在一部分问题:

  • 如何实现按键时长与跳跃高度绑定?
  • 如何限制跳跃?例如人物不在地面上时无法进行跳跃。
  • 在空中碰撞到墙体后如果仍然向墙体方向施加速度(一直按住方向键)的话,人物并不会下落,而是粘在墙体上,无法动弹。

希望能在之后的学习中解决这些问题。

物理环境监测及 Gizmos 绘制

物理环境检测

本节课创建了一个名为PhysicsCheck的通用组件,用于检测物理上的碰撞。该组件(类)中实现了一个Check方法,用于检测 GameObject 是否处于地面上,并将结果保存到isGround公共字段中。为了保证运行时的持续检测,应该在Update方法中调用Check方法。
那么如何进行检测呢?可以使用Physics2D中的一些静态方法,这些静态方法有的是方形检测,有的是胶囊形检测,这里使用的是圆形检测,来看代码:isGroud = Physics2D.OverlapCircle((Vector2)transform.position + bottomOffset, checkRadius, groundLayer);
在这里解释一下各个参数,transform.positon的详细位置,选中一个物体,按下 w 键就可以看到了,但是记得 Toggle Tool Handle Position 是 Pivot 而不是 Center 模式;bottomOffset是一个Vector2D类型的字段,在这里可以理解为用方便我们手动调整圆心位置的一个变量;checkRadius就是要检测的圆形区域的半径;groundLayer则是要检测的层级,这个层级选中 GameObject 后,在 Inspector 窗口中的 Layer,不在这个层级中的物体不会触发检测,所以我们可以为我们的地板自定义一个 Ground 层级。
检测逻辑完成了,现在我们通过了解isGround的值就可以知道当前的 GameObject 是否处于地面上了。那么回到 PlayerController.cs 中,更改下Jump方法中施加力的逻辑:只有PhysicsCheck组件中的isGround值为true时,即人物站在地板上时,才能施加瞬时力。

Gizmos 绘制

不过我们要怎么才能知道这个用来检测碰撞的球形的大小呢?回到 PhysicsCheck.cs 中,实现OnDrawGizmosSelected方法即可绘制出这个球形。该方法有固定写法,这里直接贴出来:

1
2
3
4
private void OnDrawGizmosSelected()
{
Gizmos.DrawWireSphere((Vector2)transform.position + bottomOffset, checkRadius);
}

创建人物基本动画


这里有一只爱丽丝

希望本文章能够帮到您~


Unity学习笔记-3
https://map1e-g.github.io/2023/11/06/unity-learning-3/
作者
MaP1e-G
发布于
2023年11月6日
许可协议