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里如果有未定义其他类型,记得补充

相关推荐
天人合一peng38 分钟前
unity 通过代码修改button及其名字字体的属性
unity·游戏引擎
GLDbalala4 小时前
Unity基于自定义管线实现经典经验光照模型
unity·游戏引擎
心疼你的一切7 小时前
Unity异步编程神器:Unitask库深度解析(功能+实战案例+API全指南)
深度学习·unity·c#·游戏引擎·unitask
呆呆敲代码的小Y9 小时前
【Unity 实用工具篇】 | Book Page Curl 快速实现翻书效果
游戏·unity·游戏引擎·u3d·免费游戏·翻书插件
AC梦1 天前
unity中如何将UI上的字高清显示
ui·unity
小贺儿开发1 天前
Unity3D 智慧城市管理平台
数据库·人工智能·unity·智慧城市·数据可视化
June bug2 天前
【领域知识】休闲游戏一次发版全流程:Google Play + Apple App Store
unity
星夜泊客2 天前
C# 基础:为什么类可以在静态方法中创建自己的实例?
开发语言·经验分享·笔记·unity·c#·游戏引擎
dzj20212 天前
PointerEnter、PointerExit、PointerDown、PointerUp——鼠标点击物体,则开始旋转,鼠标离开或者松开物体,则停止旋转
unity·pointerdown·pointerup
心前阳光2 天前
Unity 模拟父子关系
android·unity·游戏引擎