Unity中的2D层级显示问题

1.层级显示

使用素材为免费或自制

本文章只用于学习和记录

在Unity2D游戏中可能出现以下情况



贴图的前后关系不正确
可以通过控制图片的层级来解决
本示例中杰西卡和树木都是搭载了图片的空物体,背景为Tilemap
新建脚本PositionSortRenderer

public class PositionSortRenderer : MonoBehaviour
{
    [SerializeField]	//序列化,私有变量也能显示在Inspector面板中
    private int sortingOrderBase = 5000;	//大参数方便后续计算
    private Renderer myRenderer;  //声明一个Renderer
    private void Awake()
    {
        myRenderer = gameObject.GetComponent<Renderer>();
    }

    private void LateUpdate()   //在角色和场景内所有物体(包括摄像机)完成移动后进行
    {
        myRenderer.sortingOrder = (int)(sortingOrderBase - transform.position.y);//根据y左边方向计算
        							//这里个人感觉sortingOrderBase用0也行,但正数方便计算且节省性能
        							//个人感觉可以将减法优化为加法
    }
}

注意这里是在LateUpdate() 中进行层级运算
Unity应当在层级内的所有物体运动完成和所有物理计算如碰撞这些完成之后再进行与图片等渲染有关的处理,否则图片在运动和碰撞检测时会不断抽搐,这里不深入细讲,LateUpdate()会在FixedUpdate()Update()之后运行。
注意这里需要将代码搭载到需要排序且有Sprite Renderer的图片上,而非空物体
运行后发现有效果

但仍有问题

这是参与计算的是图片的中心点(锚点)位置的原因


那么解决方法存在两种

2.通过代码解决

因为图片默认为中心点,那么只需要在计算时减去中心点到图片底部这一段距离即可
优化PositionSortRenderer

//public class PositionSortRenderer : MonoBehaviour
//{
    //[SerializeField]
    //private int sortingOrderBase = 5000;
    [SerializeField]
    private int offset = 0;
    //private Renderer myRenderer;
    //private void Awake()
    //{
        //myRenderer = gameObject.GetComponent<Renderer>();
    //}

    //private void LateUpdate()   //在角色和场景内所有物体(包括摄像机)完成移动后进行
    //{
        myRenderer.sortingOrder = (int)(sortingOrderBase - transform.position.y - offset);
    //}
//}

这里Offset可以每个图片微调,直接获取图片高度一半的方法还在尝试

3.通过修改图片的锚点来修改

也可以直接修改图片的中心点

单体图片点击即可修改

分割的图片需要打开Sprite Editor选中修改,但单体图片也可进行相同操作

中间的蓝色圆圈即为图片的中心,可以直接拖拽进行修改

修改后如下

4.继续优化

其实那些位置不变的物体只需要计算一次层级,只有类似玩家这类不断移动的物体才需要持续计算层级,静止物体只计算一侧层级能节省许多性能开销
继续优化PositionSortRenderer

//public class PositionSortRenderer : MonoBehaviour
//{
    ......
    [SerializeField]
    private bool runOnlyOnce = false;
    //private Renderer myRenderer;
   ......
    //private void LateUpdate()   //在角色和场景内所有物体(包括摄像机)完成移动后进行
    //{
        //myRenderer.sortingOrder = (int)(sortingOrderBase - transform.position.y - offset);
        if (runOnlyOnce)
        {
            Destroy(this);	//这里摧毁了脚本
        }
    //}
//}

这样勾选了Run Only Once的图片进行一次层级运算后便会销毁
这里层级信息被直接赋值给了Unity

因为大部分静态对象没有必要每帧都进行层级运算,避免后续计算导致性能开销

角色这类需要运动的对象不要勾选,需要一直对其进行层级运算

5.再次优化

角色的层级运算也不必每帧进行,因为大部分玩家其实是观察不出来的,如果我们通过计时器来定时计算玩家这类会移动的图片还能省下不少性能。
继续优化PositionSortRenderer

//public class PositionSortRenderer : MonoBehaviour
//{
    ......
    private float timer;
    private float timerMax = 0.1f;
    //private Renderer myRenderer;
    ......
    //private void LateUpdate()   //在角色和场景内所有物体(包括摄像机)完成移动后进行
    //{
        timer -= Time.deltaTime;
        if (timer <= 0f)
        {
            timer = timerMax;
            //myRenderer.sortingOrder = (int)(sortingOrderBase - transform.position.y - offset);
            //if (runOnlyOnce)
            //{
                //Destroy(this);
            //}
        }
    //}
//}

这里我设置为0.1秒计算一次,也可自行修改
这样就能得到正确的显示结果

posted @ 2022-04-07 22:18  AlphaIkaros  阅读(1480)  评论(0编辑  收藏  举报