天天看點

UGUI世界坐标轉換為UI本地坐标(遊戲Hud的實作)

近來在遊戲實作一些功能時,原以為很簡單的東西卻難以實作,需要查大量資料才能去實作它,浪費了時間,降低了開發進度

深感基礎之薄弱,究其原因是在學習新知識時淺嘗辄止,基礎不牢靠,很多知識沒有經過驗證就跳過它,這對于學習來說是非常忌諱的,是以部落客在此警醒自己,今後的學習要舉一反三尋根問底。~~欲登高而窮目,勿築台于浮沙!時間:2019年5月20日(520)

實作世界坐标的原理是: 世界坐标和UGUI的坐标分屬兩個坐标系,他們之間是無法進行轉換的,需要通過螢幕坐标系來進行轉換(因為螢幕坐标是固定的),即先将遊戲場景中的世界坐标通過遊戲場景Camera轉化為螢幕坐标(Camera.main.WorldToScreenPoint(point)),再通過UICamera将該螢幕坐标轉換為UI本地坐标(RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, screenPoint, uiCamera, out localPoint))

疑問?

那麼初學的小白們(部落客也是小白)可能會疑惑UGUI為什麼會有UICamera,因為UGUI的Canvas的RenderMode有三種模式,一般預設為Overlay(全覆寫),另一種為Camera。

  1. 當RenderMode為Overlay時,UI坐标系和螢幕坐标系是一樣的,則不需要通過UICamera來轉換,直接将第一步得到的螢幕坐标指派給Hud的localPosition就可以了。
  2. 一般遊戲中要實作3D物體在在UI之上時,就不能用畫布全覆寫模式,而是要再建立一個Camera來單獨渲染UI,Clear Flags為Depth Only。當RenderMode為Camera時,則需要以上兩步來得到本地坐标。

注意:最後指派給Hud的本地坐标是localPosition而不是position

拓展:世界坐标、本地坐标、視口坐标,各種坐标系要了解清楚,在學習shader時也是有用的

以下是實作hud跟随3D物體的腳本,隻是測試用,不是開發中的代碼,腳本挂在任意遊戲物體上 demo下載下傳

using UnityEngine;

public class SceneFollowUI : MonoBehaviour
{
    public RectTransform hud;            //Hud
    public RectTransform canvas;//UI的父節點
    public Transform parent;    //跟随的3D物體
    public Camera uiCamera;     //UICamera 

    Vector3 offset;      //hud偏移量
    Vector3 cachePoint;
    float originalDistance;
    float factor = 1;
    bool visiable = true;

    void Start()
    {
        offset = hud.localPosition - WorldPointToUILocalPoint(parent.position);
        cachePoint = parent.position;
        originalDistance = GetCameraHudRootDistance();
        UpdateVisible();
    }

    void LateUpdate()
    {
        if (cachePoint != parent.position)
        {
            float curDistance = GetCameraHudRootDistance();
            factor = originalDistance / curDistance;
            UpdatePosition(); //更新Hud位置
            UpdateScale();    //更新Hud的大小
            UpdateVisible();  //更新Hud是否可見,根據需求設定:factor或者根據和相機距離設定,一定範圍内可見,相機視野範圍内可見 等等
        }
    }


    private void UpdateVisible()
    {
        
    }

    private void UpdatePosition()
    {
        hud.localPosition = WorldPointToUILocalPoint(parent.position) + offset * factor;
        cachePoint = parent.position;
    }

    private void UpdateScale()
    {
        hud.localScale = Vector3.one * factor;
    }

    private float GetCameraHudRootDistance()
    {
        return Vector3.Distance(Camera.main.transform.position, parent.position);
    }

    private Vector3 WorldPointToUILocalPoint(Vector3 point)
    {
        Vector3 screenPoint = Camera.main.WorldToScreenPoint(point);
        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, screenPoint, uiCamera, out localPoint);
        return localPoint;
    }
}

           
UGUI世界坐标轉換為UI本地坐标(遊戲Hud的實作)

繼續閱讀