• UI指示屏幕外目标方向的功能


    有时后敌人或者传送门等位置超出屏幕外,为了指示这些物体的位置,需要有UI标识这些物体的位置。

    这里采用怪物离屏幕边缘最近的点。另一种方式是怪物与玩家的位置连线与屏幕边框的交点,这里暂时不考虑。

    using JetBrains.Annotations;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices.WindowsRuntime;
    using System.Security.AccessControl;
    using UnityEngine;
    using UnityEngine.Animations;
    
    /// <summary>
    /// 图标类型
    /// </summary>
    public enum IconType
    {
        OpendDoor,   //正在打开的门
        EliteDoor,   //精英怪门
        NpcDoor,     //NPC门
        BossDoor,     //Boss门
        RandomDoor,  //问号门
        HomeDoor
    }
    
    /// <summary>
    /// 预制物体和图标类型的对应
    /// </summary>
    [System.Serializable]
    public class PointIconTypePair
    {
        public IconType iconType;
        public GameObject prefab;
    }
    
    /// <summary>
    /// 图标与目标物体
    /// </summary>
    public class PointIconPair
    {
        public Transform icon;
        public Transform target;
        public Transform cycleFigure;//圆圈指向,用于指向目标位置
    
        public PointIconPair(Transform icon,Transform target)
        {
            this.icon = icon;
            this.target = target;
            cycleFigure = icon.Find("CycleFigure_Image");
        }
    
        /// <summary>
        /// 按照固定屏幕空间计算设置图标的位置
        /// </summary>
        /// <param name="distanceToEdge"></param>
        public void UpdateWithScreenSpaceOverlay(float distanceToEdge)
        {
            if (!icon || !target) return;
    
            Vector3 iPos;
            Vector3 tPos;
    
            bool isAlive = SetAlive(out iPos,  distanceToEdge,out tPos);
    
            if (!isAlive) return;
    
            icon.position = iPos;
    
            CycleFigureTarget(tPos);
        }
    
        /// <summary>
        /// 按照固定屏幕空间计算设置图标的位置
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="up"></param>
        /// <param name="down"></param>
        public void UpdateWithScreenSpaceOverlay(float left,float right,float up,float down)
        {
            if (!icon || !target) return;
    
            Vector3 iPos;
            Vector3 tPos;
    
            bool isAlive = SetAlive(out iPos,out tPos,left,right,up,down);
    
            if (!isAlive) return;
    
            icon.position = iPos;
    
            CycleFigureTarget(tPos);
        }
    
        /// <summary>
        /// 按照相机屏幕空间设置图标的位置
        /// </summary>
        /// <param name="distanceToEdge"></param>
        /// <param name="rect"></param>
        /// <param name="cam"></param>
        public void UpdateWithScreenSpaceCamera(float distanceToEdge, RectTransform rect, Camera cam)
        {
            if (!icon || !target) return;
    
            ////////////////////////////
    
            Vector3 iPos;
            Vector3 tPos;
    
            bool isAlive = SetAlive(out iPos, distanceToEdge,out tPos);
    
            if (!isAlive) return;
    
            var t = Vector2.zero;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, iPos, cam, out t);
            icon.GetComponent<RectTransform>().anchoredPosition = t;
    
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, tPos, cam, out t);
            CycleFigureTarget(t);
        }
    
        /// <summary>
        /// 相机空间设置设置图标位置
        /// </summary>
        /// <param name="distanceToEdge"></param>
        /// <param name="rect"></param>
        /// <param name="cam"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="up"></param>
        /// <param name="down"></param>
        public void UpdateWithScreenSpaceCamera(RectTransform rect, Camera cam, float left, float right, float up, float down)
        {
            if (!icon || !target) return;
    
            ////////////////////////////
    
            Vector3 iPos;
            Vector3 tPos;
    
            bool isAlive = SetAlive(out iPos, out tPos, left, right, up, down);
    
            if (!isAlive) return;
    
            var t = Vector2.zero;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, iPos, cam, out t);
            icon.GetComponent<RectTransform>().anchoredPosition = t;
    
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, tPos, cam, out t);
            CycleFigureTarget(t);
        }
    
        /// <summary>
        /// 设置激活状态,根据是否在屏幕内,激活,返回的值就是激活状态
        /// </summary>
        public bool SetAlive(out Vector3 camSpacePos,float distanceToEdge,out Vector3 targetCamSpacePos)
        {
            return SetAlive(out camSpacePos,out targetCamSpacePos,distanceToEdge,distanceToEdge,distanceToEdge,distanceToEdge);
        }
    
        /// <summary>
        /// 获取目标物体与icon的转换在屏幕空间内的位置
        /// </summary>
        /// <param name="camSpacePos"></param>
        /// <param name="targetCamSpacePos"></param>
        /// <param name="left">离屏幕左边缘的间隔</param>
        /// <param name="right">离屏幕右边缘的间隔</param>
        /// <param name="up">离屏幕上边缘的间隔</param>
        /// <param name="down">离屏幕下边缘的间隔</param>
        /// <returns></returns>
        public bool SetAlive(out Vector3 camSpacePos,out Vector3 targetCamSpacePos, float left,float right,float up,float down)
        {
            camSpacePos = new Vector3();
            targetCamSpacePos = new Vector3();
    
            Vector3 canvasPos = Camera.main.WorldToScreenPoint(target.position);
    
            float width = UnityEngine.Screen.width;
            float height = UnityEngine.Screen.height;
    
            Vector3 iPos = canvasPos;
    
            if (iPos.x > 0 && iPos.x < width && iPos.y > 0 && iPos.y < height)//如果在屏幕区域内,那么隐藏物体,不做位置更新
            {
                icon.gameObject.SetActive(false);
                return false;
            }
    
            /*if (!iconPair.icon.gameObject.activeSelf) */
            icon.gameObject.SetActive(true);
    
            if (iPos.x > width - right) iPos.x = width - right;
            else if (iPos.x < left) iPos.x = 0 + left;
    
            if (iPos.y > height - up) iPos.y = height - up;
            else if (iPos.y < down) iPos.y = 0 + down;
    
            camSpacePos = iPos;
            targetCamSpacePos = canvasPos;
    
            return true;
        }
    
        void CycleFigureTarget(Vector3 targetPos)
        {
            if (!cycleFigure) return;
            Vector3 dir = targetPos - cycleFigure.position;dir.z = 0;
            float angle = Vector3.SignedAngle(Vector3.right, dir, Vector3.forward);
            Quaternion rotation = Quaternion.Euler(0, 0, angle);
            cycleFigure.rotation = rotation;
        }
    }
    
    /// <summary>
    /// 动态图标,指示物体的位置
    /// </summary>
    public class PointIconUI : MonoBehaviour
    {
        public List<PointIconTypePair> icons=new List<PointIconTypePair>();
        public Dictionary<IconType,List<PointIconPair>> iconPairs;
    
        //public float distanceToEdge;//距离边缘的宽度
    
        [Header("icon离四个边缘的空隙大小")]
        public float left;
        public float right;
        public float up;
        public float down;
    
        [Space]
        [HideInInspector]
        public Canvas canvas;
        //public RectTransform canvas;
        private void Awake()
        {
            iconPairs = new Dictionary<IconType, List<PointIconPair>>();
            foreach(PointIconTypePair typePair in icons)
            {
                if (iconPairs.ContainsKey(typePair.iconType)) continue;
                iconPairs.Add(typePair.iconType, new List<PointIconPair>());
            }
            Debug.Log(UnityEngine.Screen.width + "  ********  " + UnityEngine.Screen.height);
            //Debug.Log(iconPairs.Count);
        }
    
        /// <summary>
        /// 更新图标的位置,如果目标物体在屏幕外,那么显示图标在对应的边缘
        /// 如果目标物体在屏幕内,那么隐藏图标
        /// </summary>
        private void Update()
        {
            if(canvas.renderMode==RenderMode.ScreenSpaceOverlay)
                UpdateWithScreenSpaceOverlay();
            else
                UpdateWithScreenSpaceCamera();
        }
    
        void UpdateWithScreenSpaceOverlay()
        {
            foreach (List<PointIconPair> list in iconPairs.Values)
            {
                foreach (PointIconPair iconPair in list)
                {
                    //iconPair.UpdateWithScreenSpaceOverlay(distanceToEdge);
                    iconPair.UpdateWithScreenSpaceOverlay(left, right, up, down);
                }
            }
        }
    
        void UpdateWithScreenSpaceCamera()
        {
            foreach (List<PointIconPair> list in iconPairs.Values)
            {
                foreach (PointIconPair iconPair in list)
                {
                    //iconPair.UpdateWithScreenSpaceCamera(distanceToEdge, transform.GetComponent<RectTransform>(), canvas.worldCamera);
                    iconPair.UpdateWithScreenSpaceCamera(transform.GetComponent<RectTransform>(), canvas.worldCamera, left, right, up, down);
                }
            }
        }
    
        /// <summary>
        /// 添加一系列图标
        /// </summary>
        /// <param name="type"></param>
        /// <param name="targets"></param>
        public void CreateIcon(IconType type,List<Transform> targets)
        {
            foreach(Transform trans in targets)
            {
                CreateIcon(type,trans);
            }
        }
    
        //添加一个图标
        public bool CreateIcon(IconType type,Transform target)
        {
            if (!iconPairs.ContainsKey(type)||!target) return false;
            //获取一个type对应的iconTypePair
            PointIconTypePair typePair = icons.Find(item => item.iconType == type);
            if (typePair == null|| !typePair.prefab) return false;
    
            //实例化一个iconPair下的预制物体
            GameObject icon = Instantiate(typePair.prefab, transform);
            icon.gameObject.SetActive(true);
    
            //将预制物体添加到字典下对应的类型的列表中
            iconPairs[type].Add(new PointIconPair(icon.transform,target));
            return true;
        }
    
        //清除所有图标
        public void Clears()
        {
            foreach(List<PointIconPair> list in iconPairs.Values)
            {
                if (list == null) continue;
                foreach(PointIconPair iconPair in list)
                {
                    Destroy(iconPair.icon.gameObject);
                    Destroy(iconPair.target.gameObject);
                }
                list.Clear();
            }
        }
    }
  • 相关阅读:
    0625jQuery练习:权限基础1:查询员工对应角色、修改员工对应角色
    0624jQuery练习:三级联动—时间
    0622jQuery基础:常用属性
    0621jQuery基础:基础属性
    0621jQuery练习:三级联动
    0621jQuery练习:弹窗
    0621jQuery基础:事件
    数据库连接-登录
    javaScript中的DOM操作及数组的使用
    设置日期对象(年-月-日 时-分-秒)实现菱形的拼接
  • 原文地址:https://www.cnblogs.com/xiaoahui/p/12854222.html
Copyright © 2020-2023  润新知