Когда вы добавляете, изменяете или удаляете скрипт (или DLL) в Unity, все затронутые сборки перекомпилируются и перезагружаются.Когда вы входите и выходите из режима воспроизведения, сборки также перезагружаются.Это приводит к тому, что все статические переменные очищаются, поскольку они принадлежат загруженной сборке и больше нигде не сохраняются.
Чтобы сохранить изменения после перезагрузки сборки, Unity должна быть в состоянии сохранить данные (переменные-члены) вдиск, а затем снова заполнить их после восстановления всего.К счастью, во многих случаях это делается автоматически.Базовый класс EditorWindow
уже помечен как [Serializable]
, поэтому нет необходимости также отмечать наш дочерний класс.Далее, все переменные, которые необходимо сохранить, также должны быть сериализуемыми.Простые типы данных, такие как string и int, являются сериализуемыми, но некоторые типы, такие как Rect, не являются таковыми, поэтому ваш список не будет сохранен, даже если он является частью экземпляра (не является статичным).См. Руководство по Unity - Сериализация скриптов .Обратите внимание, что правила для классов EditorWindow
немного отличаются от правил для сериализации классов MonoBehaviour
.Например, частные переменные сериализуются без атрибута [SerializeField]
, по крайней мере, в моей версии Unity 2018.1.0f2.
Попробуйте следующий код, чтобы лучше понять:
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
namespace PersistChangesThroughAssemblyLoad
{
public class MyEditorWindow : EditorWindow
{
Vector2 buttonStartPosition = new Vector2(0, 0);
Vector2 buttonStartSize = new Vector2(100f, 40f);
int yOffset = 10;
// All data types which should be peristent, need to be
// serializable, Vector2 is, but Rect is not.
List<Vector2> buttonPositions = new List<Vector2>();
List<Vector2> buttonSizes = new List<Vector2>();
[MenuItem("Window/MyEditorWindow")]
static void Init()
{
MyEditorWindow window = GetWindow<MyEditorWindow>("MyWindow");
LogMessage(window, "Window will be opened via the menu item.");
window.Show();
}
void OnEnable()
{
LogMessage("Window is enabled (either after opening or after assembly reload/recompile).");
}
void OnDisable()
{
LogMessage("Window is disabled (either when being closed or because the assembly is about to reload/recompile).");
}
void OnGUI()
{
if (GUILayout.Button("Add Button"))
{
buttonStartPosition.y += buttonStartSize.y + yOffset;
AddNewButton(buttonStartPosition, buttonStartSize);
}
for (int i = 0; i < buttonPositions.Count; i++)
{
string buttonName = "Button " + i;
if (GUI.Button(new Rect(buttonPositions[i], buttonSizes[i]), buttonName))
{
LogMessage(buttonName + " was clicked!");
}
}
}
void AddNewButton(Vector2 position, Vector2 size)
{
buttonPositions.Add(position);
buttonSizes.Add(size);
LogMessage("Added new button. Total count: " + buttonPositions.Count);
}
void LogMessage(string message)
{
LogMessage(this, message);
}
static void LogMessage(Object context, string message)
{
Debug.Log("Window [" + context.GetInstanceID() + "]: " + message);
}
}
}
Обратите внимание на идентификаторы экземпляра, зарегистрированные в консоли.При создании нового окна из меню идентификатор изменяется, но если окно является сериализуемым, оно сохраняется в режиме воспроизведения.Такой подход поможет вам пройти долгий путь, поскольку большинство данных можно разбить на простые типы данных.Также удобно создавать собственные структуры и помечать их атрибутом [Serializable]
следующим образом:
[System.Serializable]
public struct MyRect
{
public float x, y, width, height;
}
Кроме этого, можно записать данные в EditorPrefs в OnDisable и загрузитьэто в OnEnable.