UnityTips:使用反射调用内部方法拓展编辑器

大家都知道Unity是一个C/C++的游戏引擎,C#只是Unity提供的脚本层。因此大部分功能都是通过C#来调用底层的C++代码的。而一些朋友可能不知道的是,其实Unity的C#代码中也有很多方法是我们不能直接调用的非公共方法,一个常见的情景是在拓展Editor时,除了Unity提供的公共方法之外,我们还可以通过反射的方式,调用一些Unity提供的内部方法来实现一些特殊的功能。
至于Unity的C#代码都有哪些内容,各位可以在这里找到答案:
https://github.com/MattRix/UnityDecompiled
当然C#部分的代码并没有什么实际的操作,但是它能告诉我们有哪些方法我们可以调用。
一个有趣的例子就是如何在Editor中完全关闭Gizmo呢?一个很简单但是我们正常情况下无法调用的方法就是来干这事的。

internal static extern void SetGizmoEnabled(int classID, string scriptClass, int gizmoEnabled);

所以,我们就可以通过C#的反射机制,在自己的脚本中调用Editor内封装的非公共方法来实现。

forcefield2233456789336.gif

using System;
using System.Collections;
using System.Reflection;
using UnityEditor;

public class SceneViewGizmos
{

    #region 方法

    [MenuItem("temp/Disable All Gizmos")]
    private static void DisableAllSceneGizmos()
    {
        ToggleGizmos(false);
    }

    [MenuItem("temp/Enable All Gizmos")]
    private static void EnableAllSceneGizmos()
    {
        ToggleGizmos(true);
    }

    private static void ToggleGizmos(bool gizmosOn)
    {
        int val = gizmosOn ? 1 : 0;
        Assembly asm = Assembly.GetAssembly(typeof(Editor));
        Type type = asm.GetType("UnityEditor.AnnotationUtility");

        if (type == null)
        {
            return;
        }

        MethodInfo getAnnotations = type.GetMethod("GetAnnotations", BindingFlags.Static | BindingFlags.NonPublic);
        MethodInfo setGizmoEnabled = type.GetMethod("SetGizmoEnabled", BindingFlags.Static | BindingFlags.NonPublic);
        MethodInfo setIconEnabled = type.GetMethod("SetIconEnabled", BindingFlags.Static | BindingFlags.NonPublic);
        var annotations = getAnnotations.Invoke(null, null);

        foreach (object annotation in (IEnumerable)annotations)
        {
            Type annotationType = annotation.GetType();
            FieldInfo classIdField = annotationType.GetField("classID", BindingFlags.Public | BindingFlags.Instance);
            FieldInfo scriptClassField = annotationType.GetField("scriptClass", BindingFlags.Public | BindingFlags.Instance);
            if (classIdField != null && scriptClassField != null)
            {
                int classId = (int)classIdField.GetValue(annotation);
                string scriptClass = (string)scriptClassField.GetValue(annotation);
                setGizmoEnabled.Invoke(null, new object[] { classId, scriptClass, val });
                setIconEnabled.Invoke(null, new object[] { classId, scriptClass, val });
            }
        }
    }

    #endregion
}
posted @ 2017-07-07 12:36  慕容小匹夫  阅读(2609)  评论(1编辑  收藏  举报