美文网首页
Unity中,当物体在屏幕外时,在屏幕边缘显示它的方位

Unity中,当物体在屏幕外时,在屏幕边缘显示它的方位

作者: 全新的饭 | 来源:发表于2024-03-27 18:17 被阅读0次

    用法

    需在游戏开始时创建PosCursorSys,游戏结束时销毁PosCursorSys。
    通过CreatePosCursor为特定的target transform创建一个对应的posCursor
    其中cursorGoTemplate是一个UIGo预制体,通常是一个图标。

    通过上述方式创建PosCursor后,需在合适的时机(一般是销毁target transform时)调用DestroyPosCursor,传入前述返回值将相应PosCursor同步销毁。

    具体代码

    PosCursorSys.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PosCursorSysModel
    {
        public Canvas Canvas;
        public float RefPosZ => Canvas.planeDistance;
        public Camera UICam => Canvas.worldCamera;
    }
    public class PosCursorSys
    {
        private PosCursorSysModel _model;
        private List<PosCursor> _cursors;
    
        public PosCursorSys(PosCursorSysModel model)
        {
            _model = model;
            _cursors = new List<PosCursor>();
            MonoSys.Instance.AddLateUpdateEvent(LateUpate);
        }
        public void Destroy()
        {
            MonoSys.Instance.RemoveLateUpdateEvent(LateUpate);
    
            foreach (var cursor in _cursors)
            {
                cursor.Destroy();
            }
            _cursors.Clear();
            _cursors = null;
    
            _model = null;
        }
    
        private void LateUpate()
        {
            foreach (var cursor in _cursors)
            {
                cursor.UpdatePosAndActive();
            }
        }
    
        public PosCursor CreatePosCursor(Transform target, GameObject cursorGoTemplate, Vector2 cursorSize)
        {
            var model = new PosCursorModel()
            {
                WorldCam = Camera.main,
                UICam = _model.UICam,
                Target = target,
                CursorGoTemplate = cursorGoTemplate,
                CursorSize = cursorSize,
                RefPosZ = _model.RefPosZ,
                MinScreenPos = Vector2.zero,
                MaxScreenPos = new Vector2(Screen.width, Screen.height),
                CursorParent = _model.Canvas.transform
            };
            var cursor = new PosCursor(model);
            _cursors.Add(cursor);
            return cursor;
        }
        public void DestroyPosCursor(PosCursor posCursor)
        {
            posCursor?.Destroy();
            _cursors.Remove(posCursor);
        }
    }
    

    PosCursor.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PosCursorModel
    {
        public Camera WorldCam;
        public Camera UICam;
        public Transform Target;
        public GameObject CursorGoTemplate;
        public Vector2 CursorSize;
        public float RefPosZ;
        public Vector2 MinScreenPos;
        public Vector2 MaxScreenPos;
    
        public Transform CursorParent;
    }
    
    public class PosCursor
    {
        private PosCursorModel _model;
        private GameObject _cursorGo;
        public PosCursor(PosCursorModel model)
        {
            _model = model;
    
            _cursorGo = GOPool.Instance.GetInstance(_model.CursorGoTemplate);
            _cursorGo.transform.SetParent(_model.CursorParent);
            _cursorGo.transform.localPosition = Vector3.zero;
            _cursorGo.transform.localRotation = Quaternion.identity;
            _cursorGo.transform.localScale = Vector3.one;
        }
        public void Destroy()
        {
            GOPool.Instance.RecycleInstance(_model.CursorGoTemplate, _cursorGo);
            _cursorGo = null;
            _model = null;
        }
    
        public void UpdatePosAndActive()
        {
            var screenPos = _model.WorldCam.WorldToScreenPoint(_model.Target.transform.position);
            screenPos = LimitInScreen(screenPos, out bool isHorizontalInScreen, out bool isVerticalInScreen, out bool isInLeft, out bool isInDown);
            bool isInScreen = isHorizontalInScreen && isVerticalInScreen;
            if (!isInScreen)
            {
                screenPos.z = _model.RefPosZ;
                var uiPos = _model.UICam.ScreenToWorldPoint(screenPos);
                _cursorGo.transform.position = uiPos;
    
                _cursorGo.transform.localPosition += new Vector3(_model.CursorSize.x * 0.5f * (isHorizontalInScreen ? 0 : (isInLeft ? 1 : -1)),
                                                                  _model.CursorSize.y * 0.5f * (isVerticalInScreen ? 0 : (isInDown ? 1 : -1)), 0);
            }
            _cursorGo.SetActive(!isInScreen);
        }
    
        private Vector3 LimitInScreen(Vector2 pos, out bool isHorizontalInScreen, out bool isVerticalInScreen, out bool isInLeft, out bool isInDown)
        {
            isHorizontalInScreen = true;
            isVerticalInScreen = true;
            isInLeft = false;
            isInDown = false;
    
            if (pos.x <= _model.MinScreenPos.x)
            {
                pos.x = _model.MinScreenPos.x;
                isInLeft = true;
                isHorizontalInScreen = false;
            }
            if (pos.x >= _model.MaxScreenPos.x)
            {
                pos.x = _model.MaxScreenPos.x;
                isInLeft = false;
                isHorizontalInScreen = false;
            }
            if (pos.y <= _model.MinScreenPos.y)
            {
                pos.y = _model.MinScreenPos.y;
                isInDown = true;
                isVerticalInScreen = false;
            }
            if (pos.y >= _model.MaxScreenPos.y)
            {
                pos.y = _model.MaxScreenPos.y;
                isInDown = false;
                isVerticalInScreen = false;
            }
            return pos;
        }
    }
    

    相关文章

      网友评论

          本文标题:Unity中,当物体在屏幕外时,在屏幕边缘显示它的方位

          本文链接:https://www.haomeiwen.com/subject/nopytjtx.html