Unity自定义编辑器播放模式下二维数组值丢失问题
Unity二维数组序列化丢失值的问题
问题现象
开发玩具项目时,Unity自定义编辑器中,枚举、int、一维数组的值能在关闭Unity后正常保留,但二维数组(bool[,]或int[,])的值总是丢失,即使将其设为私有并添加[SerializeField]标签也无法解决。
相关代码
StaticBlockData.cs(ScriptableObject脚本)
using UnityEngine; namespace Scriptable { [System.Serializable] [CreateAssetMenu(fileName = "Block", menuName = "Scriptable/Data")] public class StaticBlockData : ScriptableObject { public BlockValue e_blockValue = 0; public int i_blockCount = 0; public bool[] b_slots = new bool[9]; public bool[,] b_slots2 = new bool[3,3]; } }
BlockShapeCustomEditor.cs(自定义编辑器脚本)
using Scriptable; using UnityEditor; using UnityEngine; namespace FACustomEditor { [CustomEditor(typeof(StaticBlockData)), CanEditMultipleObjects] public class BlockShapeCustomEditor : Editor { public override void OnInspectorGUI() { StaticBlockData blockData = (StaticBlockData)target; blockData.e_blockValue = (BlockValue)EditorGUILayout.EnumPopup("Block Value", blockData.e_blockValue); blockData.i_blockCount = EditorGUILayout.IntSlider("Block Count", blockData.i_blockCount, 1, 9); EditorGUILayout.LabelField("Block Shape"); EditorGUILayout.BeginHorizontal(); for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) { blockData.b_slots[x + (y * 3)] = EditorGUILayout.Toggle(blockData.b_slots[x + (y * 3)], GUILayout.MaxWidth(20)); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.LabelField("Block Shape2"); EditorGUILayout.BeginHorizontal(); for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) { blockData.b_slots2[x, y] = EditorGUILayout.Toggle(blockData.b_slots2[x, y], GUILayout.MaxWidth(20)); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); } EditorGUILayout.EndHorizontal(); if (GUI.changed) { EditorUtility.SetDirty(blockData); } } } }
问题原因
Unity的内置序列化系统不支持多维数组(如bool[,]这种矩形数组),仅支持一维数组、自定义可序列化类/结构体,以及Unity内置的可序列化集合类型(如List<T>)。ScriptableObject的持久化依赖该序列化系统,因此二维数组的内容无法被正确保存。
解决方案
方案1:用一维数组模拟二维结构
继续沿用你已经实现的b_slots思路,通过索引计算(x + y * 宽度)来访问二维数据,这种方式能被Unity正常序列化。
方案2:自定义可序列化的二维容器类
创建一个封装一维数组的可序列化类,提供二维索引的访问方式:
[System.Serializable] public class BoolGrid { public int width = 3; public int height = 3; public bool[] values = new bool[9]; // 提供二维索引器,方便像二维数组一样访问 public bool this[int x, int y] { get => values[x + y * width]; set => values[x + y * width] = value; } }
然后修改StaticBlockData:
public BoolGrid b_slots2 = new BoolGrid();
编辑器中访问逻辑改为blockData.b_slots2[x, y]即可,这样数据能被正常序列化保存。
额外优化:替换过时的保存方式
新版本Unity中EditorUtility.SetDirty已被标记为过时,建议在修改数据前调用Undo.RecordObject来确保修改被正确记录:
// 在修改blockData前添加 Undo.RecordObject(blockData, "Modify Block Shape Data"); // 后续修改代码... // 移除原有的EditorUtility.SetDirty,无需额外调用,Undo系统会自动处理保存
内容的提问来源于stack exchange,提问作者It's a Doge
相关产品推荐
相关产品推荐

