背景,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,
}