如何保存一个二维数组,作为变量检查器的一部分?

How to save a two-dimensional array, as part of the variable inspector?

我有一个包含一些变量的组件。重新启动 Unity 时将保存变量。 (整数,颜色,浮点数)

using UnityEngine;
using System.Collections;

public class Grid : MonoBehaviour
{
    public float startX = 0;
    public float startZ = 0;

    public int width = 1000;
    public int height = 1000;

    public float boxWidth = 32.0f;
    public float boxHeight = 32.0f;

    public float px;
    public float pz;

    public Color color = Color.white;
    public bool[,] map;

    void OnDrawGizmos()
    {
        if (map != null)
        {
            Vector3 pos = transform.position;

            px = pos.x + startX;
            pz = pos.z + startZ;

            Gizmos.color = color;

            Vector3 size = new Vector3(boxWidth, 0f, boxHeight);

            for (int x = 0; x < width; x++)
            {
                for (int z = 0; z < height; z++)
                {
                    if (map[x, z])
                    {
                        Gizmos.DrawCube(new Vector3(px + x * boxWidth, pos.y + 1, pz + z * boxHeight), size);
                    }
                    else
                    {
                        Gizmos.DrawWireCube(new Vector3(px + x * boxWidth, pos.y + 1, pz + z * boxHeight), size);
                    }
                }
            }
        }
    }
}

要编辑变量,我有我的检查员:

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor (typeof(Grid))]
public class GridEditor : Editor
{
    Grid grid;

    public void OnEnable()
    {
        grid = (Grid)target;
        SceneView.onSceneGUIDelegate += GridUpdate;

        if (grid.map == null)
        {
            grid.map = new bool[grid.width, grid.height];
            for (int x = 0; x < grid.width; x++)
            {
                for (int y = 0; y < grid.height; y++)
                {
                    grid.map[x, y] = false;
                }
            }
        }
    }

    public void OnDisable()
    {
        SceneView.onSceneGUIDelegate -= GridUpdate;
    }

    private int lastX = -1;
    private int lastZ = -1;
    void OnSceneGUI()
    {
        Event e = Event.current;
        Camera camera = Camera.current;

        Vector3 mousePos =  Vector3.zero; // = camera.ScreenToWorldPoint(new Vector3(e.mousePosition.x, e.mousePosition.y, distance));

        if (EventType.KeyDown == e.type && KeyCode.LeftControl == e.keyCode)
        {

            Ray ray = camera.ScreenPointToRay(new Vector3(e.mousePosition.x, -e.mousePosition.y + camera.pixelHeight, 0));
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 2550f))
            {
                mousePos = hit.point;
            }

            int x = Mathf.RoundToInt((mousePos.x - grid.px)/grid.boxWidth);
            int z = Mathf.RoundToInt((mousePos.z - grid.pz)/grid.boxHeight);

            if (x >= 0 && x < grid.width && z >= 0 && z < grid.height)
            {
                if (x != lastX || z != lastZ)
                {
                    grid.map[x, z] = !grid.map[x, z];
                    lastX = x;
                    lastZ = z;
                    SceneView.RepaintAll();
                }
            }
        }
    }

    public override void OnInspectorGUI()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label(" Start x ");
        grid.startX = EditorGUILayout.FloatField(grid.startX, GUILayout.Width(50));
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label(" Start z ");
        grid.startZ = EditorGUILayout.FloatField(grid.startZ, GUILayout.Width(50));
        GUILayout.EndHorizontal();


        GUILayout.BeginHorizontal();
        GUILayout.Label(" Grid Width ");
        grid.width = EditorGUILayout.IntField(grid.width, GUILayout.Width(50));
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label(" Grid Height ");
        grid.height = EditorGUILayout.IntField(grid.height, GUILayout.Width(50));
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label(" Box Width ");
        grid.boxWidth = EditorGUILayout.FloatField(grid.boxWidth, GUILayout.Width(50));
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label(" Box Height ");
        grid.boxHeight = EditorGUILayout.FloatField(grid.boxHeight, GUILayout.Width(50));
        GUILayout.EndHorizontal();

        if (GUILayout.Button("Open Grid Window", GUILayout.Width(255)))
        {   
           GridWindow window = (GridWindow) EditorWindow.GetWindow(typeof (GridWindow));
           window.Init();
        }

        SceneView.RepaintAll();
    }
}

不幸的是,我无法弄清楚如何存储一个二维数组(map[])的boolean,所以他在重启Unity时仍然存在。所有我来它是为了对文件进行序列化并在启动应用程序时查找文件。 (数组可以很大 1000x20)也许你可以提出一个更好的主意?谢谢!请原谅我的英语。

问题实际上与数据类型无关,例如地图,在你的情况下。你可以试试ScriptableObject class,它不需要附加到一些游戏对象

从 ScriptableObject 派生一个 class 并将 [Serializable] 属性添加到 class

[Serializable]
class MyData: ScriptableObject
{
     public bool[,] map;
     void OnEnable() { 
         //... do something to initialise the map or reload the map
     }
}

实例化对象保存数据

//in this case MyData contains your map data
var data = SciptableObject.CreateInstance(typeof(MyData));

保存到Unity数据库:

AssetDatabase.CreateAsset(data,  "Assets/SomeFolder/abc.asset");
AssetDatabase.SaveAssets()
AssetDatabase.Refresh();

检查资产中是否已经有一些资产:

var data = AssetDatabase.LoadAssetAtPath("Assets/SomeFolder/abc.asset",
    typeof(SomeData));
if(data != null) {
   //Your own logic to consume the map or whatever data
}

这样,当 Unity 重新启动时,所有变量都将被保存,您可以在 class 上添加 [InitializeOnLoad] 属性以使其自动加载。并且unity里面可以看到abc.asset文件,使用自定义编辑器编辑地图也是小菜一碟。