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

Все вводимые в инспекторе данные надо проверять на корректность.
И Unity это делает. В частности сверяет тип вводимых данных с типом переменной, которой они будут присвоены.
Например в поле типа int нельзя ввести текст или десятичное число.
А если нам нужны дополнительные проверки?

Есть у нас, к примеру, такой класс:


using UnityEngine;

public class Unit : MonoBehaviour
{
	[SerializeField]
	private string _name = "NoName";
	public string unitName
	{
		get{return _name;}
		set
		{
			_name = value;
			if(string.IsNullOrEmpty(_name))
				_name = "NoName";
		}
	}
	[SerializeField]
	private int _price = 10;
	public int price
	{
		get{return _price;}
		set
		{
			_price = value;
			if(_price < 1)
				_price = 1;
		}
	}
	[SerializeField]
	private float _health = 100f;
	public float health
	{
		get{return _health;}
		set
		{
			_health = Mathf.Clamp(value, 0f, 100f);
		}
	}
	//...code...
}
В свойствах есть проверки, и это отлично работает в коде:

unit.unitName = ""; //Присвоит "NoName"
unit.price = -10;	//Присвоит 1
unit.health = 1000; //Присвоит 100
Но совершенно не мешает указать некорректные данные в редакторе


Чтобы донести проверку до редактора Unity используем CustomEditor.
Создадим скрипт с наследованием от класса Editor (пространство имён UnityEditor).
Все скрипты редактора должны быть в папке "Editor".
Точная иерархия не важна, главное, чтобы в пути была папка "Editor".

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Unit))]
public class UnitEditor : Editor
{
	public override void OnInspectorGUI()
	{
		DrawDefaultInspector();
	}
}
Имя класса редактора для Unity значения не имеет, но для удобства используется ИмяКомпонентаEditor
В атрибуте [CustomEditor] указывается класс, для которого предназначен данный редактор.
Метод "OnInspectorGUI" вызывается при обновлении инспектора.
"DrawDefaultInspector" - отрисовка стандартного инспектора для нашего класса.
Unity и без нас делает это по-умолчанию. Нам же нужно внедрить проверку данных, поэтому вместо "DrawDefaultInspector" пишем свой вариант.
Для начала нам нужно получить компонент, который мы редактируем (тот, который сейчас висит на выбранном объекте).
Он хранится в переменной "target".
Unit unit = target as Unit;
Но вставлять это в "OnInspectorGUI" мы не будем. Нам не нужно получать компонент каждый апдейт инспектора.
Лучше объявим приватную переменную в нашем скрипте редактора и получим компонент в событии "OnEnable".
Событие "OnEnable" в скриптах редактора вызывается при выборе объекта, на котором висит редактируемый компонент.

private Unit _unit = null;

void OnEnable()
{
	_unit = target as Unit;
}
Отлично. Теперь у нас есть ссылка на компонент, можно приступать к написанию инспектора с проверками.
Для отрисовки полей будем использовать класс EditorGUILayout. (Можно использовать и GUILayout, если нужных элементов нет в GUI редактора).
В случае использования Layout элементы GUI идут друг за другом и нам не нужно расчитывать их точное положение.
В "OnInspectorGUI" выводим наши поля:

_unit.unitName = EditorGUILayout.TextField("Name", _unit.unitName);
_unit.price = EditorGUILayout.IntField("Price", _unit.price);
_unit.health = EditorGUILayout.FloatField("Health", _unit.health);
Все необходимые проверки проводятся в свойствах при присвоении значения.

9293