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
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM