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 @   慕容小匹夫  阅读(2666)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示