You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:47:03