using System; using System.Reflection; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace Rokid.MRC { public class UIPanelBase : MonoBehaviour { private RectTransform rectTransform; public bool FollowCam; public float CamDistance = 1.3f; #if UMR public bool UseForUMR; #endif public bool is3DPanel; void Update() { OnUpdate(); } public virtual void OnInit() { rectTransform = GetComponent(); //GraphicRaycaster设置 #if UMR //因为Package中没办法获取UXR的类(非Package,并在主工程中),此处暂时用反射的方式添加 if(UseForUMR) { BaseRaycaster curRayCaster = GetComponent(); Type tp = curRayCaster.GetType(); //Type rkType = Type.GetType("Rokid.UXR.RKGraphicRaycaster"); Assembly assembly = Assembly.GetEntryAssembly(); assembly = Assembly.GetExecutingAssembly(); assembly = Assembly.GetCallingAssembly(); assembly = Assembly.GetAssembly(tp); assembly = GetAssembly("Rokid.Unity.XR"); Type rkType = assembly.GetType("Rokid.UXR.RKGraphicRaycaster"); if(rkType == null) { Debug.LogError("No RKGraphicRaycaster In Project"); } else { if(tp != rkType) { Destroy(curRayCaster); gameObject.AddComponent(rkType); } } } #endif //界面类型 Canvas canvas = GetComponent(); if(is3DPanel) { canvas.renderMode = RenderMode.WorldSpace; } else { canvas.renderMode = RenderMode.ScreenSpaceOverlay; } } private Assembly GetAssembly(string name) { Assembly[] allAssb = AppDomain.CurrentDomain.GetAssemblies(); for(int i = 0;i < allAssb.Length;i++) { if(allAssb[i].FullName.Contains(name)) { return allAssb[i]; } } return null; } public virtual void OnOpen() { } public virtual void OnClose() { } public virtual void OnUpdate() { if(FollowCam) { UpdatePanelPose(); } } private void UpdatePanelPose() { if(Camera.main == null) { return; } //相机前方多远距离 Vector3 disPos = Camera.main.transform.forward * CamDistance; Vector3 temp = Camera.main.transform.position + disPos; //UI界面朝向相机 transform.rotation = Quaternion.LookRotation(Camera.main.transform.forward); //获取整个UI界面4个角的位置 Vector3[] corners = new Vector3[4]; rectTransform.GetWorldCorners(corners); //判断4个点是否在屏幕内 if(!IsVisible(corners)) { //不在屏幕内,则缓动到屏幕中 TweenPosition.Begin(gameObject, transform.position, temp, 0.3f); } else { //在屏幕内,则计算UI界面与相机的距离,保持在固定距离 float dist = Vector3.Distance(transform.position, Camera.main.transform.position); if(dist > CamDistance + 0.2f && dist > CamDistance - 0.2f) { transform.position = new Vector3(transform.position.x, transform.position.y, temp.z); } } } private bool IsVisible(Vector3[] worldPositions) { int index = 0; for(int i = 0;i < worldPositions.Length;i++) { if(IsGameObjectInCameraView(worldPositions[i])) index++; } return index >= 3; } public static bool IsGameObjectInCameraView(Vector3 pos, Camera camera = null) { if(camera == null) camera = Camera.main; if(camera == null) return false; Vector3 targetObjViewportCoord = camera.WorldToViewportPoint(pos); if(targetObjViewportCoord.x > 0 && targetObjViewportCoord.x < 1 && targetObjViewportCoord.y > 0f && targetObjViewportCoord.y < 1 && targetObjViewportCoord.z > camera.nearClipPlane && targetObjViewportCoord.z < camera.farClipPlane) return true; return false; } } }