Unity2d 遮蔽和障碍物系统原理及障碍物副本地图实现
在大多数 2D 游戏中,遮蔽和障碍物系统是不可或缺的元素,它能让游戏场景更加逼真。然而,真正了解其原理的人却并不多。本文将详细介绍 Unity2D 遮蔽和障碍物系统的原理,并通过一个障碍物副本地图的实例,帮助大家更深入地理解这一系统。
背景
尽管我玩过各种各样的游戏,但对于 2D 游戏中的遮蔽和障碍物系统,一直有一种“不识庐山真面目,只缘身在此山中”的感觉,总觉得它们的存在是理所当然的,尤其是障碍物系统。例如,在游戏中高山不可跨越、河流无法直接通过,这些设定似乎是自然而然的。或许这与中国的教育方式有关,我们在做事时往往很少去探究背后的原因。
直到自己尝试开发和实现 2D 游戏中的遮蔽和障碍物系统时,我才意识到它们是真实且需要深入研究的。此时,我开始反思:为什么 2D 游戏中会存在遮蔽和障碍物呢?其实,障碍物的存在相对容易理解,就像现实中我们无法爬到高山上或凭空穿过河流一样。
其原理基础在于,人类生活在真实的三维世界,而 2D 系统实际上是一种简化的三维模拟系统,简化的部分就是高度值。在这个模拟系统中,为了让玩家获得更真实的体验,通常会采用上帝视角,即从上方俯视观看系统。这样一来,就产生了一个问题:如何在 2D 系统中模拟 3D 系统的高度呢?这就需要一些技巧来欺骗我们的大脑。
下面通过一个例子来具体说明。在游戏世界中有一棵树,首先,角色不能走到树上,这意味着树本身是一个不可通过的障碍物,即角色无法到达树所在的坐标;其次,当人走到树下时,从上帝视角观察,根据视觉几何透视原理,人应该在树的背面,也就是被树所遮挡。这就是 2D 系统中遮蔽和障碍物系统的基本原理。
实现
遮蔽系统
目前流行的游戏引擎大多通过显卡实现图形渲染,因此都拥有高度值,即 z 值。Unity2D 作为 3D 的简化版本,具备相机的概念,我们所说的上帝模式实际上就是摄像机所看到的视口。
在场景中,我们可以通过调整不同精灵的 z 值,轻松实现不同深度的遮蔽效果。相比以前的 2D 引擎可能需要通过渲染顺序来完成遮蔽功能,Unity2D 提供了更强大的工具,使得实现完美的遮蔽系统变得更加容易。具体实现方法就是在 2D 系统中设置 Z 值。
障碍物系统
谈到障碍物系统,就不得不提及系统的寻路算法,因为障碍是寻路算法的基础,如果没有障碍,也就无需进行寻路。目前可供选择的寻路算法有很多,例如 A 算法或基于网格的寻路算法。关于 A 寻路算法的文章有很多,其基本原理是将地图转换成网格矩阵,通过网格矩阵来标识是否为障碍物。
由于地图通常较大,障碍物是随着场景地图中的元素确定的,对于复杂地图的寻路和障碍物设置,必须通过地图编辑器来实现,因此很多游戏都自带地图编辑器,其中设置地图中的障碍物系统是重要的一环。
这里我们借鉴深蓝色右手的思路,采用另一种方式来实现障碍物,即副本地图。需要注意的是,这里所说的副本地图是指游戏场景分层地图,并非我们熟知的魔兽世界中的副本场景。
实际上,场景地图可以分为多个层,简单的分层包括背景地图层、遮蔽层和副本地图层(即障碍物层)。在障碍物层中,我们可以使用不同的颜色来表示不同的障碍物。通过屏幕图层取色算法,根据图层中不同的颜色,我们可以实现不同的游戏逻辑,例如判断角色是否可以移动到某个位置、是否为传送点、是否为飞行地图等。
以下是图层取色的详细代码,供大家参考:
if (Input.GetMouseButton(0))
{
Vector3 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero);
if (hit.collider != null)
{
Debug.Log("Target Position: " + hit.collider.gameObject.transform.position);
// 可添加其他所需操作
SpriteRenderer bg = hit.collider.gameObject.GetComponent<SpriteRenderer>();
Texture2D t2d = bg.sprite.texture; // 读取图片资源
Color c = t2d.GetPixel((int)Input.mousePosition.x, (int)Input.mousePosition.y); // 获取图片 xy 坐标处的颜色
Debug.Log("color: " + c + " mousePosition : " + Input.mousePosition + " w:" + t2d.width + " y:" + t2d.height);
}
}
实际原理很简单,就是进行碰撞检测,然后结合 Texture2D 的像素取色。需要注意的是,要将取色 sprite 的 BoxCollider 和 Texture Type 设置为 Advance,否则无法使用 GetPixel 方法。
总结
在实际应用中,遮蔽系统的实现远比本文介绍的复杂,我将在后续文章中给出具体思路和实现方法。
有时候我会反思,儿童时期的我们总是充满好奇心,喜欢问很多“为什么”,但成年后我们逐渐失去了这种思考的源泉。之前关于寻路算法的系列文章,很多同学留言表示看不懂,仔细思考后,我认为这其实是正常的。就像写书一样,作者需要经过学习、实践、思考和总结的过程,最终形成文字,还需要反复修订和修改,这是一个耗时耗力的学习过程。因此,在付出的时间和精力不同的情况下,获得知识的多少也是成正比的。仅仅通过阅读文章,而不亲自动手实践和反复思考,想要掌握某个知识点确实存在一定难度。当然,这也可能与作者的水平和语言组织能力有关。所以,对于大家来说,“革命尚未成功,同志仍需努力”!