欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

[UNITY二三事_001] RaycastTarget 编辑器

程序员文章站 2022-07-08 17:36:16
目录整活代码废话整活RaycastTarget是Graphic类型的组件的一个成员, 点击之类的事件会发射射线查找开启了RaycastTarget的Graphic对象,并且排序获得最前面的Graphic,而这个功能默认是开启的…会导致奇怪的遮挡问题, 比如某个按钮点击不了开启太多RaycastTarget也会导致性能问题.因此我做了一个编辑器将当前场景(或预制体模式)下的所有开启了RaycastTarget的Graphic对象可视化,并且在EditorWindow中列举,可快速选择对象,开关R...

整活

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

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

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

这个想法来自雨松MOMO: UGUI研究院之有效解决RaycastTarget勾选过多的烦恼(二十三), 我只是在这个基础上改进了工作流程.
[UNITY二三事_001] 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

相关标签: Unity学习实践