当前位置: 移动技术网 > 科技>操作系统>windows > [UNITY二三事_001] RaycastTarget 编辑器

[UNITY二三事_001] RaycastTarget 编辑器

2020年07月28日  | 移动技术网科技  | 我要评论

整活

RaycastTarget是Graphic类型的组件的一个成员, 点击之类的事件会发射射线查找开启了RaycastTarget的Graphic对象,并且排序获得最前面的Graphic,而这个功能默认是开启的…

  • 会导致奇怪的遮挡问题, 比如某个按钮点击不了
  • 开启太多RaycastTarget也会导致性能问题.

因此我做了一个编辑器将当前场景(或预制体模式)下的所有开启了RaycastTarget的Graphic对象可视化,并且在EditorWindow中列举,可快速选择对象,开关RaycastTarget功能.

这个想法来自雨松MOMO: UGUI研究院之有效解决RaycastTarget勾选过多的烦恼(二十三), 我只是在这个基础上改进了工作流程.
截图

代码

  • 注册 SceneView.duringSceneGui 委托
    • 获得当前场景/预制体编辑模式中所有的Graphic对象
    • 按Root分类
    • 在Scene窗口中绘制开启了RaycastTarget的Graphic对象
  • OnGUI中绘制EditorWindow
using UnityEngine;
using System.Collections.Generic;
using Sirenix.Utilities.Editor;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;
using UnityEngine.UI;

namespace XFrameworkEditor
{
    /// <summary>
    /// 雨松MOMO: https://www.xuanyusong.com/archives/4291
    /// Unity会对所有勾选RaycastTarget的组件发出射线, 然后在排序找到最前面的。所以RaycastTarget越少越好
    /// </summary>
    public class RaycastTargetEditorWindow : EditorWindow
    {
        static Vector3[] _fourCorners = new Vector3[4];
        private static Graphic[] _graphics;
        private static bool _inited = false;
        private static Dictionary<GameObject, List<Graphic>> _rootToGraphics = new Dictionary<GameObject, List<Graphic>>();

        [MenuItem("功能列表/UI RaycastTarget编辑器 %F11")]
        static void ShowWindow()
        {
            var window = (RaycastTargetEditorWindow)EditorWindow.GetWindow(typeof(RaycastTargetEditorWindow), false, "UI RaycastTarget编辑器", true);
            window.Show();
        }

        /// <summary>
        /// 绘制编辑器
        /// </summary>
        private void OnGUI()
        {
            var selectGo = Selection.activeGameObject;
            GUILayout.BeginVertical();
            foreach (var rootToGraphics in _rootToGraphics)
            {
                GUILayout.Label(rootToGraphics.Key.name, SirenixGUIStyles.BoldLabel);
                foreach (var graphic in rootToGraphics.Value)
                {
                    var currentGraphicGo = graphic.gameObject;
                    var selectThis = currentGraphicGo == selectGo;

                    if (selectThis)
                        GUILayout.BeginHorizontal(GUI.skin.box);
                    else
                        GUILayout.BeginHorizontal();

                    if (graphic.raycastTarget)
                        GUI.color = Color.white;
                    else
                        GUI.color = Color.white * 0.7f;

                    var newRaycastTargetState = GUILayout.Toggle(graphic.raycastTarget, "", GUILayout.Width(15));
                    if (newRaycastTargetState != graphic.raycastTarget)
                    {
                        Undo.RecordObject(graphic, "Graphic RaycastTarget");
                        graphic.raycastTarget = newRaycastTargetState;
                        EditorUtility.SetDirty(graphic);
                    }

                    var currentContent = $"{currentGraphicGo.name} ({graphic.GetType().Name})";
                    if (GUILayout.Button(currentContent, SirenixGUIStyles.Button))
                        Selection.activeGameObject = currentGraphicGo;

                    GUILayout.EndHorizontal();
                    GUILayout.Space(5);
                }
                GUILayout.Space(20);
            }
            GUILayout.EndVertical();
            GUI.color = Color.white;
        }

        private void Update()
        {
            if (!_inited)
            {
                _inited = true;
                SceneView.duringSceneGui -= OnSceneGUI;
                SceneView.duringSceneGui += OnSceneGUI;
            }
        }

        private void OnInspectorUpdate()
        {
            Repaint();
        }

        private void OnDestroy()
        {
            SceneView.duringSceneGui -= OnSceneGUI;
            _inited = false;
        }

        /// <summary>
        /// 获得当前场景的Graphics数据
        /// </summary>
        private static void OnSceneGUI(SceneView view)
        {
            var stage = PrefabStageUtility.GetCurrentPrefabStage();
            if (stage != null)
                _graphics = stage.FindComponentsOfType<Graphic>();
            else
                _graphics = GameObject.FindObjectsOfType<Graphic>(true);

            SortGraphics();
            DrawGraphics();
        }

        /// <summary>
        /// 在编辑器中绘制Graphics轮廓
        /// </summary>
        private static void DrawGraphics()
        {
            Handles.color = Color.red;
            foreach (Graphic g in _graphics)
            {
                if (g.raycastTarget)
                {
                    var rectTransform = g.transform as RectTransform;
                    rectTransform.GetWorldCorners(_fourCorners);
                    for (int i = 0; i < 4; i++)
                        Handles.DrawLine(_fourCorners[i], _fourCorners[(i + 1) % 4]);
                }
            }

            Handles.color = Color.white;
        }

        private static void SortGraphics()
        {
            _rootToGraphics.Clear();
            foreach (var graphic in _graphics)
            {
                var rootGo = graphic.transform.root.gameObject;
                if (!_rootToGraphics.ContainsKey(rootGo))
                    _rootToGraphics.Add(rootGo, new List<Graphic>());
                _rootToGraphics[rootGo].Add(graphic);
            } 
        }
    }
}

废话

平时写点小东西,也就图一乐,大多数都是不能拿到生产上用的低能工具,但是相对来说开发效率高…稍微有点用的东西就写到博客里吧,分享一下,整理一下思路什么的.该睡了,又双叒叕熬夜了…

本文地址:https://blog.csdn.net/Jamesika/article/details/107588494

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网