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

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

  • Sorting Layer  用于设置不同层的Sprite渲染顺序
  • Order in Layer  用于设置在同一层中的Sprite渲染顺序
  • 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 / 5 ); 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 } 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 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 ); 46 Gizmos.color = Color.magenta; 47 Gizmos.DrawLine(floorHeightPos + Vector3.left * m_spriteHalfWidth, floorHeightPos + Vector3.right * m_spriteHalfWidth); 48 }

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



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

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

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

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



    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