Pull to refresh

Unity3D tips and tricks

Reading time 3 min
Views 23K


Было уже несколько статей подобного плана, где рассказывались разные трюки и приёмы для Unity. Что-то было совсем очевидно и только для новичков, что-то для более продвинутых товарищей. Хочу внести свою скромную лепту.


1. Подсказки по переменным.



Когда проект маленький это не актуально, но когда проект большой и над ним работает много человек можно забыть, за что именно отвечает та или иная переменная, которую задаешь в редакторе. Правильное именование помогает лишь частично, так как слишком короткое. Можно конечно писать Custom Editor и там делать подсказки для каждого типа, но для каждого класса это слишком накладно. Следующий способ позволяет решить такую задачу. Для этого мы делаем 2 классика:

TooltipAttribute.cs

using UnityEngine;

public class TooltipAttribute : PropertyAttribute
{
	public readonly string text;
	
	public TooltipAttribute(string text)
	{
		this.text = text;
	}
}


TooltipDrawer.cs

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(TooltipAttribute))]
public class TooltipDrawer : PropertyDrawer
{
	public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) {
		var atr = (TooltipAttribute) attribute;
		var content = new GUIContent(label.text, atr.text);
		EditorGUI.PropertyField(position, prop, content);
	}
}
#endif


Теперь, если нам надо чтобы в стандартном инспекторе была подсказка по нужной нам переменной — просто делаем так:

	[Tooltip("Первоначальный цвет объекта")]
	public Color color;

	[Tooltip("Скорость объекта, если отрицательная - движется задним ходом")]
	public float speed;


Результат:

На скриншоте почему-то не видно курсора мышки, подсказка появляется при наведении.

Перфекционисты, чтобы не добавлять мусор в релизный код, могут делать так:
#if UNITY_EDITOR
	[Tooltip("Скорость объекта, если отрицательная - движется задним ходом")]
#endif
	public float speed;


Хотя, на мой взгляд, это уже излишне.

Теперь, даже если через год-два надо что-то подправить в редакторе Вы быстро вспомните что это за переменная.

Вот здесь есть самурайская коллекция PropertyDrawer. Комменты на японском языке, но в принципе всё понятно.

2. Nullable types



Иногда бывает необходимо проверить наличие значения у переменной. Ну например вот так:

public class Character : MonoBehaviour 
{
    Vector3 targetPosition;
 
    void MoveTowardsTargetPosition()
    {
        if(targetPosition != Vector3.zero)
        {
            //Move towards the target position!
        }
    }
 
    public void SetTargetPosition(Vector3 newPosition)
    {
        targetPosition = newPosition;
    }
}


Но что, если нашему герою надо прийти в точку (0, 0, 0)? Тогда такой код не подходит.

Надо использовать nullable type. Просто добавляем знак '?' в конце к типу, и чтобы проверить наличие используем HasValue, а чтобы получить значение — Value.

public class Character : MonoBehaviour 
{
    //Notice the added "?"
    Vector3? targetPosition;
 
    void MoveTowardsTargetPosition()
    {
        if (targetPosition.HasValue)
        {
            //Move towards the target position!
            //use targetPosition.Value for the actual value
        }
    }
 
    public void SetTargetPosition(Vector3 newPosition)
    {
        targetPosition = newPosition;
    }
}


3. Personal Log.



Этот хинт может пригодится для отладки AI, по крайней мере в моём случае это было так. Смысл хинта совсем прост — просто чтобы не рыть огромный общий лог заводим каждому юниту персональный, в нашем случае это строка (string localLog). Все важные события из жизни монстра пишем туда, а для просмотра надо просто выделить монстра в редакторе. Код для того, чтобы отображался персональный лог в инспекторе:

using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(Monster))]
public class MonsterEditor : Editor {
	Vector2 scrollPos = new Vector2(0, Mathf.Infinity);

	public override void OnInspectorGUI()
	{
		serializedObject.Update();
		Monster monster = (Monster)target;

		if (Application.isPlaying) {
			scrollPos = GUILayout.BeginScrollView (
				scrollPos, GUILayout.Height (250));
			
			GUILayout.Label (monster.localLog);
			
			GUILayout.EndScrollView ();

			if (GUILayout.Button ("Clear"))
				monster.localLog = "";
		}

		serializedObject.ApplyModifiedProperties();
		DrawDefaultInspector();
	}
}


Вот, в общем то, и всё. Теперь мы видим всё что монстр думал про нас и других монстров. Такой вот простой хинт облегчает отладку.

Буду рад, если кому-то это поможет.
Tags:
Hubs:
+22
Comments 9
Comments Comments 9

Articles