Unity编辑拓展显示自定义类型

配合自定义特性或着header可以添加注解

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System;
using Unity.VisualScripting;

#if UNITY_EDITOR

public class EditorRender
{
    public static Enum RenderEnum(FieldInfo fieldInfo, Enum value, Type type, params GUILayoutOption[] style)
    {
        var array = Enum.GetValues(type);// 直接使用  Enum[] EnumValueArr =   (Enum[])Enum.GetValues(type);  不行,这里不能用enum,存在类型转换异常,只能指定枚举类型
        Enum[] EnumValueArr = new Enum[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            EnumValueArr[i] = (Enum)Enum.Parse(type, array.GetValue(i).ToString());
        }
        int[] IntValueArr = new int[EnumValueArr.Length];
        string[] EnumDescArr = new string[EnumValueArr.Length];

        for (int i = 0; i < EnumValueArr.Length; i++)
        {
            Enum e = EnumValueArr[i];
            IntValueArr[i] = (int)Enum.Parse(type, e.ToString());
            var field = type.GetField(e.ToString());
            HeaderAttribute header = field.GetAttribute<HeaderAttribute>();
            if (header != null)
            {
                EnumDescArr[i] = header.header;
            }
            else
            {
                EnumDescArr[i] = "未定义";
            }
        }
        int selectValue = (int)Enum.Parse(type, value.ToString());
        selectValue = EditorGUILayout.IntPopup(selectValue, EnumDescArr, IntValueArr, style);
        value = (Enum)Enum.Parse(type, selectValue.ToString());
        return value;
    }

    public static object RenderValue(FieldInfo fieldInfo, Type type, object value, object defaultValue = null, params GUILayoutOption[] style)
    {
        SetDefaultValue(type, ref value, defaultValue);

        if (type == typeof(int))
        {
            return EditorGUILayout.IntField(int.Parse(value.ToString()), style);
        }
        else if (type == typeof(float))
        {
            return EditorGUILayout.FloatField(float.Parse(value.ToString()), style);
        }
        else if (type == typeof(long))
        {
            return EditorGUILayout.LongField(long.Parse(value.ToString()), style);
        }
        else if (type == typeof(string))
        {
            return GUILayout.TextArea(value as string, style);
        }
        else if (type == typeof(bool))
        {
            return GUILayout.Toggle(bool.Parse(value.ToString()), "", style);
        }
        else if (type.IsEnum)
        {
            value = EditorRender.RenderEnum(fieldInfo, (Enum)value, type, style);
            return value;
        }
        else if (value is IList)
        {
            value = RenderList(type.GetGenericArguments()[0], value as IList);
            return value;
        }
        if (value == null)
        {
            return Activator.CreateInstance(type);
        }


        return null;
    }

    public static object RenderList(Type type, IList list)
    {
        if (list == null)
        {
            return Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
        }
        for (int i = 0; i < list.Count; i++)
        {

            list[i] = RenderValue(null, type, list[i], style: GUILayout.MaxWidth(400));
            if (GUILayout.Button("X", GUILayout.MaxWidth(50)))
            {
                list.RemoveAt(i);
                GUILayout.EndHorizontal();
                break;
            }
        }
        GUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
        if (GUILayout.Button("Add", GUILayout.MaxWidth(500)))
        {
            list.Add(Activator.CreateInstance(type));
        }
        GUILayout.EndHorizontal();
        return list;

    }

    public static void SetDefaultValue(Type type, ref object value, object defaultValue)
    {
        if (value == null || string.IsNullOrEmpty(value.ToString()))
        {
            if (defaultValue != null)
            {
                value = defaultValue;
                return;
            }
            if (type == typeof(int))
            {
                value = 0;
            }
            else if (type == typeof(float))
            {
                value = 0;
            }
            else if (type == typeof(long))
            {
                value = 0;
            }
            else if (type == typeof(Single))
            {
                value = 0;
            }
            else if (type == typeof(string))
            {
                value = string.Empty;
            }
            else if (type == typeof(bool))
            {
                value = false;
            }
            else if (type == typeof(Vector3))
            {
                value = Vector3.zero;
            }
            else if (type == typeof(Vector2))
            {
                value = Vector2.zero;
            }
            else if (type.IsEnum)
            {

            }
        }
    }

    public static object RenderField(FieldInfo fieldInfo, HeaderAttribute header, object obj, params GUILayoutOption[] style)
    {
        GUILayout.BeginHorizontal(GUI.skin.button);

        GUILayout.BeginVertical();
        Type t = fieldInfo.FieldType;
        GUILayout.Label($"{fieldInfo.Name}({t.Name})");

        if (header!= null)
        {
            GUILayout.Label(header.header);
        }
        GUILayout.EndVertical();

        
        var value = RenderValue(fieldInfo, t, obj, style: style);
        GUILayout.EndHorizontal();

        return value;
    }

    public static object RenderObject(object value)
    {
        var propertyInfos = value.GetType().GetFields();
        for (int i = 0; i < propertyInfos.Length; i++)
        {
            var property = propertyInfos[i];
            object obj = property.GetValue(value);
            obj = EditorRender.RenderField(property, null, obj, GUILayout.MaxWidth(400));
            property.SetValue(value, obj);

            GUILayout.Space(5);
        }


        return value;
    }
}

#endif

使用方式,直接调用RenderObject就行

cs 复制代码
    private class CustomClass
    {
        public string Name;
        public int Age;
        public bool Sex;
    }
    private CustomClass m_CustomClass;


    private void OnGUI()
    {
        m_CustomClass = (CustomClass)EditorRender.RenderObject(m_CustomClass);
    }

这里用的都是变量,如果使用属性的话,将获取属性,获取属性值,写入属性值的方式修改源代码即可,RenderValue里如果有未定义其他类型,记得补充

相关推荐
叶帆14 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
久数君14 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
会思考的猴子14 天前
Unity VFX 属性 Postion 和 TargetPostion
unity
hai31524754315 天前
九章编程法 · 猜数字游戏 (GW-BASIC 重构版) *
人工智能·microsoft·游戏引擎·游戏程序
心前阳光15 天前
Unity资源导入之自动化资源导入
unity·自动化·游戏引擎
心前阳光15 天前
Unity之2021.3.45f2c1发布安卓程序遇到的问题
android·unity·游戏引擎
纪纯15 天前
PicoVR Unity Integration SDK 3.4 常用交互API
unity·游戏引擎·vr·pico
龙智DevSecOps解决方案15 天前
3A 游戏优化技术栈:如何打通引擎级分析工具与 DevOps 持续集成管线?
unity·性能优化·游戏开发·技术美术·perforce·unrealengine
葛兰岱尔15 天前
从 SolidWorks 到 Three.js,从 Inventor 到 Unity——制造业CAD模型“几何-语义一体化“转换,不再是天方夜谭!
开发语言·javascript·unity
鼎艺创新科技15 天前
三维电子沙盘中OSGB倾斜摄影数据的加载与渲染
游戏引擎·cocos2d