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

相关推荐
omegayy6 小时前
Unity 2022.3.x部分Android设备播放视频黑屏问题
android·unity·视频播放·黑屏
虾球xz9 小时前
游戏引擎学习第200天
学习·游戏引擎
woshihedayu10 小时前
虚幻引擎控制角色跟随移动方向旋转的方法
游戏引擎·虚幻
虾球xz10 小时前
游戏引擎学习第199天
学习·游戏引擎
与火星的孩子对话12 小时前
Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发
人工智能·unity·c#·游戏引擎·语音识别·宠物
向宇it12 小时前
【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍
开发语言·游戏·unity·c#·编辑器·游戏引擎
牙膏上的小苏打23331 天前
Unity Surround开关后导致获取主显示器分辨率错误
unity·主屏幕
Unity大海1 天前
诠视科技Unity SDK开发环境配置、项目设置、apk打包。
科技·unity·游戏引擎
浅陌sss1 天前
Unity中 粒子系统使用整理(一)
unity·游戏引擎
维度攻城狮2 天前
实现在Unity3D中仿真汽车,而且还能使用ros2控制
python·unity·docker·汽车·ros2·rviz2