所谓2.5D游戏,就是利用技术手段让2D精灵图片呈现3D视觉效果。今天这篇文章,将由2.5D游戏《A Place for the Unwilling》开发者Martín Pane,为大家分享在Unity 5中实现游戏场景中各精灵层级规划与遮挡的过程。
首先来看看下面的视频,了解《A Place for the Unwilling》这款2.5D游戏的最终效果:



下面是Martín Pane带来的分享。

开发《A Place for the Unwilling》游戏第一部要解决的问题就是让精灵可以围绕精灵前后移动,呈现出真实的深度感觉。SpriteRenderer组件有两个属性,可以改变场景中Sprite的渲染顺序。

Sorting Layer用于设置不同层的Sprite渲染顺序 Order in Layer用于设置在同一层中的Sprite渲染顺序


如果想实时改变多个Sprite的渲染顺序,就需要修改一些属性以便无论精灵在场景中如何移动,均以正确的顺序渲染。由于“Oder in Layer”属性仅接受整型参数,所以利用Z轴似乎是个更好的选择。

Unity中Sprite的渲染优先级如下图,从高到低:

095907htg4iy8qtrxfyyh4.png

如果两个Sprite的“Sorting Layer”和“Order in Layer”均相同,那么在3D世界坐标中离相机更近的Sprite会被先渲染。

在明白了Sprite的渲染顺序后,接下来之要写个简单的脚本更改Sprite坐标的Z值为与其Y值成固定比例即可。但在此之前,先来解释一个重要的小概念,即如何设置精灵位于地面的底部。这里“底部”就是指3D世界中对象与地面接触的部分,示例如下:

095908jzjtontor4zmyuqk.png

我们要做的是在改变Sprite坐标Y值的同时改变其Z值,上图在3D环境的效果如下图:

095908jqporerebluvskd5.png

理解了以上内容,就可以写脚本了,代码如下:

[C#] 纯文本查看 复制代码[SerializeField] private float m_floorHeight; private float m_spriteLowerBound; private float m_spriteHalfWidth; private readonly float m_tan30 = Mathf.Tan(Mathf.PI / 5); void Start() { SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>(); m_spriteLowerBound = spriteRenderer.bounds.size.y * 0.5f; m_spriteHalfWidth = spriteRenderer.bounds.size.x * 0.5f; } // Use this condition for objects that don’t move in the scene. #if UNITY_EDITOR void LateUpdate() { // Use this condition for objects that don’t move in the scene. if (!Application.isPlaying) { // Update the position in the Z axis: transform.position = new Vector3 ( transform.position.x, transform.position.y, (transform.position.y - m_spriteLowerBound + floorHeight) * m_tan30 ); } } #endif void OnDrawGizmos() { Vector3 floorHeightPos = new Vector3 ( transform.position.x, transform.position.y - m_spriteLowerBound + floorHeight, transform.position.z ); Gizmos.color = Color.magenta; Gizmos.DrawLine(floorHeightPos + Vector3.left * m_spriteHalfWidth, floorHeightPos + Vector3.right * m_spriteHalfWidth); }

095908do7rmywmrez7gm78.png

首先需要设置的是“Floor Height”,该属性决定Sprite的下边界在Y方向的偏移。 在3D世界坐标中,它用于设置Sprite在场景中的Z深度。 如果一个Sprite的底部比Sprite更高,它将被渲染在Sprite后面。

095909kjgrstutrjuo66tj.png

另一种情况是将某个Sprite作为另一个的子对象时。仍然以建筑为例,如果想为建筑增加窗户或招牌,这些附加物就不能使用与建筑相同的脚本,因为有些窗户可能位于建筑后面或顶部。这个问题很容易解决,只需创建建筑的子对象重置其坐标,并将Z坐标值设为-0.001,然后将所有需要附着在建筑上物体放置于该子对象下,将这些物体的Z坐标设为0,这样就可以与实际建筑保持0.001的距离,并且它们离相机更近。

095909cv985clp98bxsqbb.png

最终3D环境下的完整场景如下:

095909znzcncisxbttgahj.png

Unity引擎本身就已经提供了非常灵活的工具来实现这样的功能,下面来看看这种实现方式存在的一些限制,以及一些有助于改进工作流程的扩展方法。

这种实现方式最大的限制就是制作很薄的墙壁时,因为使用该方法必须将Sprite切割为多个与墙壁厚度一致的部分,以便场景中的物体可以在墙壁前后移动。示例如下:

095910y692eg7gsesgqgs9.png

对于飞行物来说可能也比较麻烦,但如果注意其摆放的位置就可以避免出现问题。还可以通过修改Sorting Layer的值让它们永远位于场景主要对象的前方或后方。

最后分享一下如何扩展这种方式以适用更多的场景。

Isometric Colliders: 根据角色在游戏中的移动方式,实现一个小脚本为角色创建一个与游戏场景的图片摆放角度一致的碰撞体。

095910enhqn511r7q7ntw6.png

IsoVector类:该类包含一些常用的方向向量(N,W,E,S,NE,NW,SE,SW),以及从自定义方向获取向量(反之亦然)的方法,或者获取给定方向的反向向量(例如输入南获取北)等。

本文介绍的内容不一定是最佳的解决方案,但也展现出了很好的学习思路,从最开始想到编写脚本调整Sprite的Z值来正确渲染一切对象,解决了一开始构建游戏场景的问题。随着继续扩展代码库,也丰富了一些自定义类来加入新功能,同时维护好项目结构。希望这篇文章对正在使用Unity开发这种等距游戏的开发者有帮助!

原文连接:https://madewith.unity.com/en/stories/what-i-learned-from-trying-to-make-an-isometric-game-in-unity
原文作者:Martín Pane
感谢Unity官方翻译组成员“CelebrationMA”对本文翻译所做的贡献。
转载请注明来源:Unity官方中文社区(forum.china.unity3d.com)。请勿私自更改任何版权说明信息。

Unite 2017 Shanghai
Unite 2017 Shanghai将于5月11 - 13日在上海国际会议中心举行。5折个人通票开售!赞助商招募已开启,愿您与我们一同打造一场Unity开发者盛会!Made with Unity展区作品征集等更多信息请访问Unite 2017 Shanghai官方网站(unite2017.csdn.net)!

Unity, 游戏, Made with Unity锐亚教育

锐亚教育 锐亚科技 unity unity教程