Блог программиста
Кастомизация редактора Unity. Проверка данных в редакторе
12.06.2017Кастомизация редактора

В прошлой статье мы рассмотрели проверку вводимых данных через свойства класса.
Но в случае с публичными свойствами, значения переменных можно изменить из любого класса, а это не всегда хорошо.
Чтобы этого избежать, можно сделать свойства приватными или убрать вовсе, но в этом случае и редактор потеряет к ним доступ и посыплет ошибками.

К счастью редактор имеет доступ к сериализуемым полям, это все публичные переменные и приватные с соответствующим атрибутом.
Приступим к изменению класса редактора из прошлой статьи.

После удаления всего неработающего и ненужного, класс примет такой вид:

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Unit))]
public class UnitEditor : Editor
{
	void OnEnable()
	{

	}

	public override void OnInspectorGUI()
	{

	}
}

Доступ к редактируемому компоненту мы теперь будем получать через свойство "serializedObject".
Необходимые поля класса можно получить с помощью функции "FindProperty", которая принимает имя переменной и возвращает объект типа "SerializedProperty".
Создадим переменные для хранения наших полей и получим их в функции "OnEnable" (Да-да, это чтобы не искать их каждое обновление инспектора).

private SerializedProperty _name = null;
private SerializedProperty _price = null;
private SerializedProperty _health = null;

void OnEnable()
{
	_name = serializedObject.FindProperty ("_name");
	_price = serializedObject.FindProperty ("_price");
	_health = serializedObject.FindProperty ("_health");
}
Для отображения полей используем знакомый нам класс "EditorGUILayout", но уже с помощью "PropertyField".
При использовании PropertyField, Unity самостоятельно определяет тип переменной и выводит соответствующее поле, применяя все атрибуты кастомизации, указанные для данной переменной.
public override void OnInspectorGUI()
{
	EditorGUILayout.PropertyField (_name);
	EditorGUILayout.PropertyField (_price);
	EditorGUILayout.PropertyField (_health);
}
Теперь нужно добавить необходимые проверки.
Получение значений осушествляется через свойства "типValue"
public override void OnInspectorGUI()
{
	EditorGUILayout.PropertyField (_name);
	if (string.IsNullOrEmpty (_name.stringValue))
		_name.stringValue = "NoName";

	EditorGUILayout.PropertyField (_price);
	if (_price.intValue < 1)
		_price.intValue = 1;

	EditorGUILayout.PropertyField (_health);
	_health.floatValue = Mathf.Clamp (_health.floatValue, 0f, 100f);
}
Всё прекрасно отображается, и проверки работают. Но стоит запустить сцену или переключиться на другой объект, как всё сбрасывается.
Происходит это потому что изменения не применены к объекту.
Исправим это, добавив в конце функции "OnInspectorGUI":
//Применение изменений
serializedObject.ApplyModifiedProperties ();
Отлично, изменения сохраняются, но чрезмерно часто. Мы заставляем Unity применять изменения, даже когда их нет.
Нам нужно проверять, были ли изменения, и если они были, то применять. Для этого используем методы "BeginChangeCheck" и "EndChangeCheck" из класса "EditorGUI".
EndChangeCheck возвращает true, если были изменены значения полей редактора, указанных между BeginChangeCheck и EndChangeCheck
public override void OnInspectorGUI()
{
	EditorGUI.BeginChangeCheck ();
	EditorGUILayout.PropertyField (_name);
	if (string.IsNullOrEmpty (_name.stringValue))
		_name.stringValue = "NoName";

	EditorGUILayout.PropertyField (_price);
	if (_price.intValue < 1)
		_price.intValue = 1;

	EditorGUILayout.PropertyField (_health);
	_health.floatValue = Mathf.Clamp (_health.floatValue, 0f, 100f);

	if (EditorGUI.EndChangeCheck ())
	{
		//Применение изменений
		serializedObject.ApplyModifiedProperties();
	}
}
На этом всё :)

12315