编辑器开发IMGUI/GUI—重新实现List的序列化实现自定义List默认值控制

背景,unity自带的序列化在数据量较大的时候很不好用,每次都要手动输入值,也没有默认值

也不能在里面嵌入一些下拉栏来选择

通过手动实现效果序列化可以设置默认值和控制下一个元素的值

但其实强烈不推荐这样做,浪费时间,GUI没有学习的价值

实现原理

IMGUI相关知识不多阐述

先把三个按钮绘制出来,添加默认,拷贝上一个,删除

因为我们是手动控制。所以显示的长度itemCount也要手动来更新

顺便通过这个枚举来判断这次添加的是哪一种添加

然后就是核心绘制List

首先声明序列化对象和属性

这个IMGUI跑不掉的

去我们的实例中拿到具体的字段,下面是我们的两个用到的数据结构

 

因为Imgui是每一帧绘制的,在绘制每一次前面监测是否有添加的动作

添加了itemCount大于了我们实际的list长度那就要扩容

通过IMGUI的反射方法去添加

然后绘制即可

源代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using UnityEngine;
//需要的空间
using UnityEditor;

//TODO:序列化 End报错 Enum.TayParse的坑
namespace EditorExtensions
{
    public class TestEditor1 : EditorWindow
    {
        private GUIStyle customStyle;

        //预设值
        private const int TYPE = 1;
        private const string ID = "Gems";
        private const int COUNT = 1;
        private const int TABLE = 0;
        private const string SHOP_ID = "";

        private const int SHOP_COUNT = 1;

        //格子宽度
        private float itemCellLen = 220;

        private float itemNameCellLen = 140;

        //测试ID
        //布局
        private Vector2 mScrollViewPos;

        private bool isHideItem = true;

        //输出
        //变量
        private static SerializedObject serializedObject;

        private static SerializedProperty items;

        //SerializeField是修饰变量 able是修饰类 必须公共才序列化
        [SerializeField] private Drawer currentDrawer;

        //两个列表的长度
        private int itemCount;
        private bool isInit = false;
        private AddType1 currentAddType = AddType1.Default;
        private Drawer currentDawer;

        #region 打开窗口

        [MenuItem("编辑器工具/补发道具")]
        public static void OpenGUIExample()
        {
            var window = GetWindow<TestEditor1>();
            window.position = new Rect(0, 0, 470, 700);
            GetWindow<TestEditor1>().Show();
        }

        #endregion

        //初始化 只有点开的时候才会使用
        private void Init()
        {
            if (isInit) return;
            //TODO:临时使用的变量
            customStyle = new GUIStyle(GUI.skin.label);
            customStyle.normal.textColor = Color.red; // 例如,将颜色更改为红色
            serializedObject = new SerializedObject(this);
            currentDrawer = new Drawer();
            currentAddType = AddType1.Default;
            //初始化各个变量
            items = serializedObject.FindProperty("currentDrawer.items");
            isInit = true;
        }

        private void OnGUI()
        {
            Init();
            //前面的是更新位置 后面的是传入的当前位置
            mScrollViewPos = GUILayout.BeginScrollView(mScrollViewPos);
            {
                serializedObject.Update();

                #region 普通Item

                GUILayout.BeginHorizontal();
                {
                    GUILayout.BeginHorizontal(GUILayout.Width(200));
                    itemCount = EditorGUILayout.IntField("发放的普通物品列表", itemCount);
                    GUILayout.EndHorizontal();


                    if (GUILayout.Button("+Default", GUILayout.Width(65)))
                    {
                        itemCount++;
                        currentAddType = AddType1.Default;
                    }

                    if (GUILayout.Button("+Copy", GUILayout.Width(60)))
                    {
                        itemCount++;
                        currentAddType = AddType1.Copy;
                    }

                    if (GUILayout.Button("-", GUILayout.Width(60)))
                    {
                        if (itemCount > 0) itemCount--;
                    }
                }
                GUILayout.EndHorizontal();
                //根据容量绘制每一个需要设置索引位置的对象
                //每次绘制前从尾部开始判断是否要删除不需要的元素
                //只有当容量减少时才会走这的逻辑 count<OnEnable count的容量
                isHideItem = EditorGUILayout.BeginFoldoutHeaderGroup(isHideItem, "");
                {
                    if (isHideItem)
                    {
                        //删除多余的
                        for (int i = items.arraySize - 1; i > itemCount - 1; i--)
                        {
                            items.DeleteArrayElementAtIndex(i);
                        }

                        GUILayout.BeginHorizontal();
                        {
                            EditorGUILayout.Space(15);
                            GUILayout.BeginVertical();
                            {
                                SerializedProperty temp;
                                SerializedProperty last = null;
                                for (int i = 0; i < itemCount; i++)
                                {
                                    GUILayout.BeginVertical("box");

                                    //容量不够 大小小于当前要绘制的下标了 
                                    if (items.arraySize <= i)
                                    {
                                        items.InsertArrayElementAtIndex(i);
                                        temp = items.GetArrayElementAtIndex(i);
                                        AddItem(i, temp, last, currentAddType);
                                    }

                                    temp = items.GetArrayElementAtIndex(i);
                                    //Step:自定义绘制
                                    GUILayout.Label($"物品{i}", customStyle);
                                    GUILayout.BeginHorizontal();
                                    GUILayout.Label("type", GUILayout.Width(itemNameCellLen));
                                    temp.FindPropertyRelative("type").intValue =
                                        EditorGUILayout.IntField(temp.FindPropertyRelative("type").intValue,
                                            GUILayout.Width(itemCellLen));
                                    GUILayout.EndHorizontal();
                                    //
                                    EditorGUILayout.BeginHorizontal();
                                    {
                                        GUILayout.Label("id", GUILayout.Width(itemNameCellLen));
                                        //ID采用两种方式输入 以下拉菜单输入为准
                                        temp.FindPropertyRelative("id").stringValue =
                                            //ID采用两种方式输入 以下拉菜单输入为准
                                            EditorGUILayout.TextField(temp.FindPropertyRelative("id").stringValue,
                                                GUILayout.Width(itemCellLen / 2));
                                    }
                                    EditorGUILayout.EndHorizontal();
                                    //
                                    GUILayout.BeginHorizontal();
                                    GUILayout.Label("count", GUILayout.Width(itemNameCellLen));
                                    temp.FindPropertyRelative("count").intValue =
                                        EditorGUILayout.IntField(temp.FindPropertyRelative("count").intValue,
                                            GUILayout.Width(itemCellLen));
                                    GUILayout.EndHorizontal();
                                    //
                                    GUILayout.BeginHorizontal();
                                    GUILayout.Label("table", GUILayout.Width(itemNameCellLen));
                                    temp.FindPropertyRelative("table").intValue =
                                        EditorGUILayout.IntField(temp.FindPropertyRelative("table").intValue,
                                            GUILayout.Width(itemCellLen));
                                    GUILayout.EndHorizontal();
                                    GUILayout.EndVertical();
                                }
                            }
                            GUILayout.EndVertical();
                        }
                        GUILayout.EndHorizontal();
                    }
                }
                EditorGUILayout.EndFoldoutHeaderGroup();
                serializedObject.ApplyModifiedProperties();

                #endregion


                serializedObject.ApplyModifiedProperties();
            }
            GUILayout.EndScrollView();
        }

        private static void AddItem(int i, SerializedProperty temp, SerializedProperty last, AddType1 currentAddType)
        {
            if (i == 0 || currentAddType == AddType1.Default)
            {
                temp.FindPropertyRelative("type").intValue = TYPE;
                temp.FindPropertyRelative("id").stringValue = ID;
                temp.FindPropertyRelative("count").intValue = COUNT;
                temp.FindPropertyRelative("table").intValue = TABLE;
            }
            else
            {
                last = items.GetArrayElementAtIndex(i - 1);
                temp.FindPropertyRelative("type").intValue =
                    last.FindPropertyRelative("type").intValue;
                temp.FindPropertyRelative("id").stringValue =
                    last.FindPropertyRelative("id").stringValue;
                temp.FindPropertyRelative("count").intValue =
                    last.FindPropertyRelative("count").intValue;
                temp.FindPropertyRelative("table").intValue =
                    last.FindPropertyRelative("table").intValue;
            }
        }
    }

    #region 需要的类

    [Serializable]
    public class Drawer
    {
        public List<Item> items;
    }

    [Serializable]
//注:可用资源的ID就是枚举
    public class Item
    {
        //不用自己输入 隐藏即可
        public int type = 0;
        public string id;
        public int count = 1;

        public int table = 0;

        //添加可用资源
        public static void AddAVToList(List<Item> list, string idEnum, int count)
        {
            Item item = new Item();
            item.type = 1;
            item.id = idEnum;
            item.count = count;
            item.table = 0;
            list.Add(item);
        }
    }

    #endregion
}

public enum AddType1
{
    Default,
    Copy,
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值