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秒計算一次,也可自行修改
這樣就能得到正確的顯示結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM