代码源自游戏《A Place for the Unwilling》

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

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

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

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

<ignore_js_op>

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

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

<ignore_js_op>

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

<ignore_js_op>

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

  1. using UnityEngine;
  2.  
  3. [ExecuteInEditMode]
  4. public class IsometricStaticObject : MonoBehaviour {
  5.  
  6. [SerializeField]
  7. private float m_floorHeight;
  8. private float m_spriteLowerBound;
  9. private float m_spriteHalfWidth;
  10. private readonly float m_tan30 = Mathf.Tan(Mathf.PI / );
  11.  
  12. void Start()
  13. {
  14. SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
  15. m_spriteLowerBound = spriteRenderer.bounds.size.y * 0.5f;
  16. m_spriteHalfWidth = spriteRenderer.bounds.size.x * 0.5f;
  17. }
  18.  
  19. // Use this condition for objects that don’t move in the scene.
  20. #if UNITY_EDITOR
  21. void LateUpdate()
  22. {
  23. // Use this condition for objects that don’t move in the scene.
  24. if (!Application.isPlaying)
  25. {
  26. // Update the position in the Z axis:
  27. transform.position = new Vector3
  28. (
  29. transform.position.x,
  30. transform.position.y,
  31. (transform.position.y - m_spriteLowerBound + m_floorHeight) * m_tan30
  32. );
  33. }
  34. }
  35. #endif
  36.  
  37. void OnDrawGizmos()
  38. {
  39. Vector3 floorHeightPos = new Vector3
  40. (
  41. transform.position.x,
  42. transform.position.y - m_spriteLowerBound + m_floorHeight,
  43. transform.position.z
  44. );
  45.  
  46. Gizmos.color = Color.magenta;
  47. Gizmos.DrawLine(floorHeightPos + Vector3.left * m_spriteHalfWidth, floorHeightPos + Vector3.right * m_spriteHalfWidth);
  48. }
  49. }

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

<ignore_js_op>

然后存储Sprite高度与宽度的半值,以便对Z坐标进行一些简单的数学运算。在《A Place for the Unwilling》游戏中使用了30度的等距切角,但您也可以将Z坐标设为与Y坐标一致,不影响游戏效果。

这里使用OnDrawGizmos方法在当前的地面高度绘制一条线,以便可以在编辑器中设置为最终的精确位置。另外,对于有些游戏运行后永远不会移动的对象,可以使用“if(!Application.isPlaying)”和“#if UNITY_EDITOR”条件在运行时保存计算结果,因为可能会有上百个Sprite同时绑定该脚本。

以上设置完成后,就可以在场景中移动Sprite并保证渲染顺序正常了,但还有两种情况需要更多的设置。

在处理中心不在中间位置的Sprite时,需要将其分为几部分。以下面的建筑为例,由于它的底部是矩形,如果整个建筑仅设置一个Floor Height值,那角色将只能沿着它前方的那面行走,并且会遮挡角色!为了解决这个问题,就需要将建筑Sprite分为两个部分,并为每一边设置不同的地面,如下图:

<ignore_js_op>

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

<ignore_js_op>

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

<ignore_js_op>

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

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

<ignore_js_op>

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

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

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

<ignore_js_op>

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

Unity2.5D Sprite层级显示遮挡问题处理的更多相关文章

  1. Unity中的2D层级显示问题

    ##1.层级显示 ###使用素材为免费或自制 本文章只用于学习和记录 在Unity2D游戏中可能出现以下情况 贴图的前后关系不正确 可以通过控制图片的层级来解决 本示例中杰西卡和树木都是搭载了图片的空 ...

  2. iOS开发UI篇-实现tableView的层级显示

     进来要实现一个tableView 的cell层级显示,网上找的思路都各不相同.下面说一下我的实现思路.  根据根标题存储cell的展开状态,添加到字典中. 话不多说,直接上代码. #define S ...

  3. eclipse包层级显示和工作空间显示

    本文两件事:设置包层级显示.设置工程的工作空间显示 一.各package包分层显示 平铺显示,实在不方便开发!也不方便查看工程包的层级结构,如下: 更换成层级显示: 二.工作空间显示 包用来区分类,工 ...

  4. 由object元素引出的事件注册问题和层级显示问题

    项目有一个双击监控视频全屏的需求,视频播放使用的是IE下的ActiveX控件,web页面中使用HTML嵌入对象元素object.预期方案如下: 1.在开发ActiveX控件时加入双击事件. 2.通过d ...

  5. 三维模型2.5D轮廓提取及遮挡部分的剔除

    轮廓提取相对容易,只需在2.5D渲染视角下,导出模型的顶点坐标以及基于视角的消隐后的三角形面,将三角面投影后合并就可得到轮廓,轮廓坐标基于2.5d图的基准坐标换算就得到.提取轮廓的在我另外一篇文章中有 ...

  6. 关于移动端开发,vedio标签层级高遮挡蒙版的解决方案

    问题描述: 使用famework7框架搭建了一个界面,然后再界面中需要使用蒙版效果,在PC端,ios测试没有问题,在Andriod播放视屏再点击显示蒙版的效果师,视频会遮盖蒙版.修改定位,z-inde ...

  7. cocos creator 场景如何透明,多个canvas层级显示

    转载地址:https://forum.cocos.com/t/creator-canvas/55373/14 Creator 版本:1.7 目标平台:WEB MOBILE 项目需要,页面做了多个Can ...

  8. vue bootstrap中modal对话框不显示遮挡打不开

    使用Vue bootstrap时,点击modal却不能弹出来,被隐藏遮挡无法显示,参考下面的这个博客的说明解决了这个问题: Heap Stack Blog(pingbook.top)Vue boots ...

  9. Query Designer:Hierarchy层级显示

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

随机推荐

  1. Python中实现按顺序遍历字典

    第一种方法: import collections d = collections.OrderedDict([('a',1),('b',2),('c',3)]) ''' 或者把上面的那一行改成: d ...

  2. phpstudy xdebug 配置

    来源:https://baijiahao.baidu.com/s?id=1607680791440431678&wfr=spider&for=pc https://www.cnblog ...

  3. Git (一)预设环境和免密登录

    背景 一直用的svn,这段时间换了之后才发现git的强大功能.缺点就是可能上手比较难一点. 接下来就带你Git入门 Git是什么? Git是目前世界上最先进的分布式版本控制系统 Git有什么特点?好用 ...

  4. (第六篇)vim编辑器的使用

    什么是 vim(window文本文档) Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用.简单的来说, vi 是老式的字处理器,不过功 ...

  5. 5.Python是怎么解释的?

    Python是怎么解释的? Python language is an interpreted language. Python program runs directly from the sour ...

  6. linux下报错:error while loading shared libraries

    linux执行bin程序报: error while loading shared libraries:libncurses.so.5: cannot open shared object file: ...

  7. Longest XXX

    Longest Common Substring Brute Force 遍历a和b所有位置的组合,向后延伸,直到遇到两个不同的字符,复杂度是\(n^3\)级别. class Solution { p ...

  8. POJ - 2251 Dungeon Master(搜索)

    You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of un ...

  9. linux下编译boost的多线程程序

    linux下面用boost库进行多线程编程,一开始总是编译不成功,花了好多的时间. 下面是一段小示例代码: //start from the very beginning,and to create ...

  10. 蓝色展开收缩悬浮QQ客服代码

    放在我的博客首页上的的预览图: 在文章区的预览图如下: 代码如下: <div class="scrollsidebar" id="scrollsidebar&quo ...