UGUI优化 RaycastTarget

这篇博客介绍了如何优化Unity UGUI的RaycastTarget属性以提高效率,包括通过编辑器扩展在Editor模式下高亮显示启用RaycastTarget的UI元素,以及在创建或添加Image、Text、Button组件时自动管理RaycastTarget状态。此外,还提供了UnityPackage资源链接供用户直接导入使用。
摘要由CSDN通过智能技术生成

优化依据:
UGUI事件会在EventSystem在Update的Process触发。UGUI会遍历屏幕中所有RaycastTarget是true的UI,然后发射线,并排序找到玩家最先触发的那个UI,再抛出事件给逻辑层去响应。
问题:
RaycastTarget如果被勾选的过多的话, 效率必然会低。
根据UGUI常用拼UI方式,提出以下需求
需求:
1.要能看到哪个模块勾选了RaycastTarget
2.创建的Image,text自动取消勾选RaycastTarget
3.已创建的Image,text如果添加了Button组件,自动勾选RaycastTarget

解决方案
Git工蜂链接,UnityPackage导入即用,懒人专属
百度网盘链接,UnityPackage导入即用,懒人专属
提取码:3n1d

需求1,普遍做法为Editor模式下,遍历所有MaskableGraphic,RaycastTarget为true的画上线框

#if UNITY_EDITOR
using UnityEngine;
using UnityEngine.UI;
namespace HengEditor
{
	/// <summary>
	/// 挂载到任意物体,为能检测射线的物体加上显示框
	/// </summary>
    public class DebugUILine : MonoBehaviour
    {
        static Vector3[] fourCorners = new Vector3[4];
        void OnDrawGizmos()
        {
            foreach (MaskableGraphic g in GameObject.FindObjectsOfType<MaskableGraphic>())
            {
                if (g.raycastTarget)
                {
                    RectTransform rectTransform = g.transform as RectTransform;
                    rectTransform.GetWorldCorners(fourCorners);
                    Gizmos.color = Color.blue;
                    for (int i = 0; i < 4; i++)
                        Gizmos.DrawLine(fourCorners[i], fourCorners[(i + 1) % 4]);

                }
            }
        }

        void Awake(){
            Destroy(gameObject);
        }
    }
}

#endif

需求2,3
首先创建一个类,判断不同情况下的优化方式

using UnityEngine;
using UnityEngine.UI;
namespace HengEditor
{
    /// <summary>
    /// 组件优化设置
    /// </summary>
    public class ComponentOptimizing
    {
        #region Image
        public static void OptimizingImage(Image image)
        {
        	//如果当前图片不是按钮,取消勾选RaycastTarget
            if (image.gameObject.GetComponent<Button>() == null)
            {
                image.raycastTarget = false;
            }

        }
        #endregion


        #region Text
        public static void OptimizingText(Text text)
        {
            if (text.gameObject.GetComponent<Button>() == null)
            {
                text.raycastTarget = false;
            }
            //是否支持富文字框架,默认不支持,有需求再手动勾选
            text.supportRichText = false;
        }
        #endregion
        #region Button
        public static void OptimizingButton(Button button)
        {
        	//判断需要添加button组件的物体是否有继承自MaskableGraphic的组件,有的话就勾选RaycastTarget
            if (button.gameObject.GetComponent<MaskableGraphic>() != null)
            {
                button.gameObject.GetComponent<MaskableGraphic>().raycastTarget = true;
            }

        }
        #endregion
      
    }
}

在Hierarchy或GameObject直接创建UI组件时,使用以下扩展
顺便将自动创建DebugUILine显示

using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace HengEditor
{
    /// <summary>
    /// Hierarchy面板创建优化
    /// </summary>
    public class HierarchyMenuItem
    {

        [MenuItem("GameObject/UI/Image")]
        static void CreatImage()
        {
            AddUI.InstanceImage();
        }

        [MenuItem("GameObject/UI/Text")]
        static void CreatText()
        {
            AddUI.InstanceText();
        }

		[MenuItem("GameObject/UI/RaycastChecker")]
        static void CreateRaycastChecker()
        {
            AddUI.InstanceRaycastChecker();
        }

    }
    /// <summary>
	/// 创建UI组件
	/// </summary>
	public class AddUI
    {
        /// <summary>
        /// 创建Image
        /// </summary>
        public static void InstanceImage()
        {
            Image image = CreateComponent<Image>();
            ComponentOptimizing.OptimizingImage(image);
        }

        /// <summary>
        /// 创建Text
        /// </summary>
        public static void InstanceText()
        {
            Text text = CreateComponent<Text>();
            ComponentOptimizing.OptimizingText(text);
        }

		/// <summary>
        /// 创建raycast检测器
        /// </summary>
        public static void InstanceRaycastChecker()
        {
            DebugUILine com = CreateComponent<DebugUILine>();
            
        }
        private static T CreateComponent<T>() where T : Component
        {
            string name = typeof(T).Name;
            GameObject go = new GameObject(name);
            Transform parent = GetUIParent();
            go.transform.SetParent(parent, false);
            T com = go.AddComponent<T>();
            return com;
        }

        private static Transform GetUIParent()
        {
            Transform select = Selection.activeTransform;
            if (select)
            {
                if (select.GetComponentInParent<Canvas>())
                {
                    return select;
                }
                else
                {
                    Canvas canvas = select.GetComponentInChildren<Canvas>();
                    if (canvas == null)
                    {
                        canvas = InstanceCanvas(select);
                    }
                    return canvas.transform;
                }
            }
            else
            {
                Canvas canvas = GetCanvasInScene();
                if (canvas == null)
                {
                    canvas = InstanceCanvas();
                }
                return canvas.transform;
            }
        }

        /// <summary>
        /// 参考PrefabStageUtility.HandleUIReparentingIfNeeded
        /// </summary>
        /// <returns></returns>
        static Canvas GetCanvasInScene()
        {
            // TODO 为什么会找不到?
            //Canvas canvas = Object.FindObjectOfType<Canvas>();
            Scene scene = SceneManager.GetActiveScene();
            foreach (GameObject go in scene.GetRootGameObjects())
            {
                // Do not search for Canvas's under the prefab root since we want to
                // have a Canvas for the prefab root
                var canvas = go.GetComponentInChildren<Canvas>();
                if (canvas != null)
                    return canvas;
            }
            return null;
        }

        /// <summary>
        /// 参考PrefabStageUtility.HandleUIReparentingIfNeeded
        /// </summary>
        /// <returns></returns>
        private static Canvas InstanceCanvas(Transform parent = null)
        {
            const string kUILayerName = "UI";
            // Create canvas root for the UI
            //todo  HideFlags.dontsave
            GameObject root = EditorUtility.CreateGameObjectWithHideFlags("Canvas", HideFlags.None);
            root.layer = LayerMask.NameToLayer(kUILayerName);
            Canvas canvas = root.AddComponent<Canvas>();
            canvas.renderMode = RenderMode.ScreenSpaceOverlay;
            root.AddComponent<CanvasScaler>();
            root.AddComponent<GraphicRaycaster>();
            if (parent)
            {
                canvas.transform.SetParent(parent, false);
            }
            return canvas;
        }
    }
}

为已存在物体添加Image,Text,Button组件时

using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
namespace HengEditor
{
    /// <summary>
    /// Inspector面板添加组件回调(优化component)
    /// </summary>
    [InitializeOnLoad]
    public class InspectorAddComponent
    {

        static InspectorAddComponent()
        {
        	//监听组件添加事件
            ObjectFactory.componentWasAdded += ComponentWasAdded;
        }

        static public void ComponentWasAdded(Component com)
        {

            switch (com.GetType().ToString())
            {
                case "UnityEngine.UI.Image":

                    ComponentOptimizing.OptimizingImage(com as Image);
                    break;
                case "UnityEngine.UI.Text":

                    ComponentOptimizing.OptimizingText(com as Text);
                    break;
                case "UnityEngine.UI.Button":

                    ComponentOptimizing.OptimizingButton(com as Button);
                    break;
                case "UnityEngine.UI.Mask":

                    ComponentOptimizing.OptimizingMask(com as Mask);
                    break;
            }
            
        }


    }

}


参考链接1
参考链接2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值