近來在遊戲實作一些功能時,原以為很簡單的東西卻難以實作,需要查大量資料才能去實作它,浪費了時間,降低了開發進度
深感基礎之薄弱,究其原因是在學習新知識時淺嘗辄止,基礎不牢靠,很多知識沒有經過驗證就跳過它,這對于學習來說是非常忌諱的,是以部落客在此警醒自己,今後的學習要舉一反三尋根問底。~~欲登高而窮目,勿築台于浮沙!時間: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。
- 當RenderMode為Overlay時,UI坐标系和螢幕坐标系是一樣的,則不需要通過UICamera來轉換,直接将第一步得到的螢幕坐标指派給Hud的localPosition就可以了。
- 一般遊戲中要實作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;
}
}
