RPG 游戏开发(4)绘制地板和NPC并实现碰撞检测
首先,我们将 Atlas 素材里一开始我们准备好的 player_1 素材拖曳到 Hierarchy 面板。这时候就会产生第二个角色。我们在 Hierarchy 面板中选中刚刚加入的 player_1,然后在 Inspector 面板中,最顶端的 player_1 改为 Test_NPC。以区分他是玩家或是 NPC,然后我们将他的坐标(Position)的 X 轴修改为 -0.2,让他出现在玩家左侧。
接下来,在 Inspector 面板中,点击 Add Component 按钮,添加一个 BoxCollider2D 元件,该元件就是用来检测物体碰撞,碰撞包括:触碰到NPC和其对话、触碰到怪物造成伤害、触碰到墙体无法继续前进等等。调整框的大小,这里我选择和我的玩家一样。 调整参数为:Offset X: 0, Y: -0.01,Size X: 0.1, Y: 0.1
制作地板
我们点击 Atlas,然后在 Inspector 面板中点击 Sprite Editor。我们找到两个合适的图标作为地板和墙体。我选择了深色的块作为墙壁,并将其命名为 wall_0;然后选择另一个较为浅色的块作为地板,将其命名为 floor_0。切割完毕之后,点击 Apply,这时候发现 Atlas 图集的小箭头多出了两个图标。
当我们将 floor_0 图块直接拖拽到 Hierarchy 面板上,默认他会出现在原点(x = 0, y = 0),也就是我们玩家的位置。这时候你会发现,我们的玩家被这个图块挡住了。
修改渲染图层
为了解决这个问题,我们需要知道一个概念:图层。在 Hierarchy 面板选择 player_0,在 Inspector 面板定位到 Sprite Renderer 元件的 Sorting Layer 项(如果没有这个属性,则是隐藏在 Additional Layer 里)点开下拉框,然后点击 Add Sorting Layer。这时候 Inspector 面板将会跳转至 Tags & Layer,并且展开 Sorting Layers 属性列。
在 Sorting Layer 点击右侧的 + 号,新建一个图层 Actor(角色)。添加完毕后,我们再点击 Hierarchy 面板中的 player_0,再找到 Inspector 面板里的 Sorting Layer。点开下拉框选择刚刚添加的 Actor,然后你的 玩家就会出现在地板前面了!
同理,对 NPC 也要执行同样的操作。
接下来,我们需要再继续复制粘贴几个地板,然后再把墙壁放上去。结果大概这样(如果你有强迫症,每个区块之间的间隔为0.16)我们现在用比较笨的方法去弄这个,后续将会使用 Tile Palette 功能进行地图绘制。
碰撞的概念
首先我们要知道几个需求,地板是没有 BoxCollider 的,所以不被考虑在内:
- 玩家不可经过踩上去的地方(碰到这些,玩家会被阻拦)
- 墙体
- NPC
- 玩家可以踩上去的地方(触发某些机制)
- 开关
- 回复泉水
- 陷阱
所以,我们需要增加两个图层(Layer)。这和 Sorting Layer 是不同的,Sorting Layer 是关于渲染的层级关系,而 Layer 可以理解为一个组别,我们需要实现的是:当玩家碰上这些块的时候,会出现什么事情。
现在,我们选择 Hierarchy 界面的 wall_0 然后在 Inspector 界面的 Layer 下拉菜单中点击 Add Layer。我们在 User Layer 中依次添加 Blocking 和 Actor 层。
点击 Hierarchy 面板中的 wall_0,然后按住 CTRL 选择 wall_1(可以多选)。如果某些需要选择的物体在 Hierarchy 面板中是连续的,可以直接长按 Shift 多选。然后 Layer 下拉菜单中选择 Blocking,这将作为我们玩家的障碍物。然后我们也要给他俩加上 BoxCollider2D 元件。
之后再选择 player_0 和 Test_NPC,将 Layer 切换为刚刚创建的 Actor 层。
别担心,之后不会那么麻烦。我们会把这些琐碎的事情交给 Tilemap 来做,但是现在为了让大家理解原理,就先搞得麻烦一点。
有了碰撞体之后,还是不能阻止玩家经过的。我们需要让角色知道“哦,这是墙体,我不能穿过去”。那要让角色知道的事情,就需要用代码来完成了。
编程
碰撞检测的编程思路是这样的:我们需要在移动的时候,往移动的方向前方投影一个看不见的方块,如果这个方块检测到障碍物,那么人物就不能向前移动。
所以我们需要声明 RaycastHit2D hit; 变量来检测。
我们在之前朝向切换和开始移动之间写上一段代码,具体位置在这里:
if (moveDelta.x > 0) |
然后我们说到,RaycastHit2D 的作用是放置一个投影,用于检测前方是否有障碍物,所以我们调用 Physic2D.BoxCast()
函数,创建一个投影块。具体检测两个轴,x 和 y。我们先检测 y 轴(上下),BoxCast() 函数需要传递 6 个参数,分别是:
- 投影块要出现的位置:角色的位置
- 投影块的大小:角色的 BoxCollider2D 的大小
- 角度:角色移动不需要角度,所以传递 0
- 方向:所需要计算的方向(这里只能计算一个轴的方向(上下、左右))。它的计算判断应该是取 x y 轴的点,然后算与原点的角度。
- 投影块的距离:我们传递绝对值,这样不管是向左走(-1)还是向右走(1)都能为 1
- 需要检测的碰撞体所在图层:检测 Blocking 和 Actor 层
当检测的投影块碰撞(collider)为空,则可以移动。代码如下
// 放置一个方块来检测,确保我们能够朝这个方向移动。如果检测为空,则表示可以移动 |
同样,我们也需要给 x 轴有同样的操作:
// 放置一个方块来检测,确保我们能够朝这个方向移动。如果检测为空,则表示可以移动 |
修改后的完整代码如下
using System.Collections; |
检测的时候,我们发现玩家居然完全不能移动,怎么回事?
因为我们检测的是 Blocking 层和 Actor 层、玩家也在 Actor 层里,所以他就检测自己,觉得“自己和自己碰撞了”。那需要解决这个问题,我们需要打开项目设置:Unity 左上角 Edit / Project Settings 然后弹出的对话框中左侧选择 Physic 2D。在右侧的属性列表中找到 Queries Start in Colliders,取消勾选。
设置结束后,运行游戏。可以发现玩家可以在地图上奔跑,然后遇到障碍物会停下了。