заполнить массив инспекторов автоматически - PullRequest
1 голос
/ 13 октября 2019

У меня есть двумерный массив (на основе сетки), и я хочу заполнить его через инспектор. Чтобы дать вам представление об игре

enter image description here

Итак, мой наземный скрипт содержит все эти ячейки.

public class Ground : MonoBehaviour
{
    public Cell[,] cells;

    private void Start()
    {
        Debug.Log(cells);
    }
}

Из-заФактически, было бы много работы, чтобы управлять всеми этими ячейками и назначить их основному сценарию, который я думал об автоматизации. Поэтому всякий раз, когда я добавляю GameObject (как дочерний элемент) и назначаю ему компонент Cell, Ground должен автоматически добавлять эту ячейку в массив. Чтобы добиться этого, я подумал о создании сценария редактора для инспектора.

[CustomEditor(typeof(Ground))]
public class GroundEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        Ground ground = (Ground)target;

        Dictionary<Vector2Int, Cell> cells = new Dictionary<Vector2Int, Cell>();
        int maximumHorizontalLength = 0;
        int maximumVerticalLength = 0;

        foreach (Transform groundCell in ground.transform)
        {
            Cell cell = groundCell.GetComponent<Cell>();

            if (cell != null)
            {
                Vector3 cellPosition = groundCell.position;
                Vector2Int cellIndices = new Vector2Int(Mathf.RoundToInt(cellPosition.x), Mathf.RoundToInt(cellPosition.z));
                cells.Add(cellIndices, cell);

                if (cellIndices.x > maximumHorizontalLength)
                {
                    maximumHorizontalLength = cellIndices.x;
                }

                if (cellIndices.y > maximumVerticalLength)
                {
                    maximumVerticalLength = cellIndices.y;
                }
            }
        }

        maximumHorizontalLength++;
        maximumVerticalLength++;

        ground.cells = new Cell[maximumHorizontalLength, maximumVerticalLength];

        for (int x = 0; x < maximumHorizontalLength; x++)
        {
            for (int y = 0; y < maximumVerticalLength; y++)
            {
                ground.cells[x, y] = cells[new Vector2Int(x, y)];
            }
        }
    }
}

Поэтому я хочу создать эту двумерную сетку перед запуском игры, чтобы сэкономить ресурсы. Я не хочу искать по тегу или типу во время игры. И я думаю, что этот подход экономит время.

К сожалению, при запуске игры Debug.Log печатает ноль. Я надеялся заполнить его этой строкой ground.cells = new Cell[maximumHorizontalLength, maximumVerticalLength]; Я что-то пропустил? Это вообще возможно?

Ответы [ 2 ]

3 голосов
/ 16 октября 2019

Многомерные массивы не поддерживаются сериализатором Unity , поэтому вам нужно будет реструктурировать способ хранения данных в каждой ячейке. Один из вариантов - создать новый пользовательский класс, производный от MonoBehaviour, чтобы сохранить эти данные и поместить их где-нибудь в сцене:

[System.Serializable]
public class CellData : MonoBehaviour
{
    [System.Serializable]
    public class CellReference
    {
        public int xPos;
        public int yPos;
        public Cell cell;

        public CellReference(Vector2Int posVal, Cell celVal)
        {
            xPos = posVal.x; yPos = posVal.y; cell = celVal;
        }
    }

    public List<CellReference> cellReferences = new List<CellReference>();
}

. Затем его можно заполнить с помощью инспектора с помощью следующих изменений в Ground и GroundEditor. классы:

public class Ground : MonoBehaviour
{
    public CellData cells;

    private void Start()
    {
        Debug.Log(cells);
    }
}

[CustomEditor(typeof(Ground))]
public class GroundEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        if (GUILayout.Button("Refresh Cell References"))
        {
            Ground ground = (Ground)target;

            ground.cells.cellReferences = new List<CellData.CellReference>();

            foreach (Transform groundCell in ground.transform)
            {
                Cell cell = groundCell.GetComponent<Cell>();

                if (cell != null)
                {
                    Vector3 cellPosition = groundCell.position;
                    Vector2Int cellIndices = new Vector2Int(Mathf.RoundToInt(cellPosition.x), Mathf.RoundToInt(cellPosition.z));

                    ground.cells.cellReferences.Add(new CellData.CellReference(cellIndices, cell));
                }
            }
        }
    }
}

Подключите скрипт CellsData к размещенному вами скрипту Ground, и он будет генерировать новый список ячеек при каждом нажатии кнопки «Обновить ссылки на ячейки» в инспекторе.

1 голос
/ 16 октября 2019

Мне кажется, проблема в том, что вы не помечаете измененный объект как грязный, поэтому Unity не сохранит ваши изменения. Так как это экземпляр сцены, вы можете пометить всю сцену как грязную или использовать Undo.RecordObject(objectToUndo, name) на самом объекте. (Он помечает только целевой объект как грязный)

Использование их в hovewer в OnInspectorGUI() не рекомендуется, поэтому вы можете сначала проверить наличие изменений, а в случае каких-либо изменений пометить его как грязное

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...