优化依据:
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;
}
}
}
}