///////////////////////////////////////////////////////Common Editor Tool wrapper class///////////////////////
public class HorizontalBlock : IDisposable
{
public HorizontalBlock(params GUILayoutOption[] options)
{
GUILayout.BeginHorizontal(options);
}
public HorizontalBlock(GUIStyle style, params GUILayoutOption[] options)
{
GUILayout.BeginHorizontal(style, options);
}
public void Dispose()
{
GUILayout.EndHorizontal();
}
}
public class IndentBlock : IDisposable
{
public IndentBlock()
{
EditorGUI.indentLevel++;
}
public void Dispose()
{
EditorGUI.indentLevel--;
}
}
public class ScrollViewBlock : IDisposable
{
public ScrollViewBlock(ref Vector2 scrollPosition, params GUILayoutOption[] options)
{
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, options);
}
public void Dispose()
{
EditorGUILayout.EndScrollView();
}
}
public class VerticalBlock : IDisposable
{
public VerticalBlock(params GUILayoutOption[] options)
{
GUILayout.BeginVertical(options);
}
public VerticalBlock(GUIStyle style, params GUILayoutOption[] options)
{
GUILayout.BeginVertical(style, options);
}
public void Dispose()
{
GUILayout.EndVertical();
}
}
EditorGUILayout.LabelField("Some Indented Stuff:");
using (new IndentBlock())
{
EditorGUILayout.LabelField("This is indented!");
}
using (new HorizontalBlock())
{
if (GUILayout.Button("Left Button")) { }
if (GUILayout.Button("Right Button")) { }
}
using (new VerticalBlock())
{
if (GUILayout.Button("Top Button")) { }
if (GUILayout.Button("Bottom Button")) { }
}
// In your editor class, define a private variable
private Vector2 _scrollViewPosition;
// In your GUI code you can easily make scroll views
using (new ScrollViewBlock(ref _scrollViewPosition))
{
for (int i = 0; i < 20; i++)
{
if (GUILayout.Button("Button " + i)) { }
}
}
/////////////////////////////////////////////////////////AnimParamsAttribute///////////////////////////////////////////
public class AnimParamsAttribute : PropertyAttribute
{
public string animatorProp;
public AnimParamsAttribute(string animatorPropName)
{
animatorProp = animatorPropName;
}
}
[CustomPropertyDrawer(typeof(AnimParamsAttribute))]
public class AnimParamsDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Reject drawing this custom attribute if property wasn't a string type
if (property.propertyType != SerializedPropertyType.String)
{
base.OnGUI(position,property,label);
return;
}
AnimParamsAttribute animParams = (AnimParamsAttribute) attribute;
SerializedProperty animProp = property.serializedObject.FindProperty(animParams.animatorProp);
if (animProp == null)
{
base.OnGUI(position, property, label);
return;
}
Animator targetAnim = animProp.objectReferenceValue as Animator;
if (targetAnim == null)
{
base.OnGUI(position, property, label);
return;
}
string propVal = property.stringValue;
int selectedIndex;
GUIContent[] popup = BuildParamList(targetAnim, propVal, out selectedIndex);
selectedIndex = EditorGUI.Popup(position, label, selectedIndex, popup);
if (selectedIndex < popup.Length && selectedIndex > -1)
propVal = popup[selectedIndex].text;
else
propVal = "";
if (propVal.Equals(property.stringValue) == false)
{
property.stringValue = propVal;
EditorUtility.SetDirty(property.serializedObject.targetObject);
}
}
private GUIContent[] BuildParamList(Animator targetAnimator, string propVal, out int selectedIndex)
{
selectedIndex = -1;
GUIContent[] paramList = new GUIContent[targetAnimator.parameterCount+1];
for (int i = 0; i < targetAnimator.parameterCount; i++)
{
AnimatorControllerParameter param = targetAnimator.parameters[i];
paramList[i] = new GUIContent(param.name);
if (param.name.Equals(propVal))
selectedIndex = i;
}
paramList[targetAnimator.parameterCount] = new GUIContent("<None>");
return paramList;
}
}
///////////////////////////////////////////////////////////////Property Drawers////////////////////////////////////////////////////////////
public class Example : MonoBehaviour {
public string playerName = "Unnamed";
[Multiline]
public string playerBiography = "Please enter your biography";
[Popup ("Warrior", "Mage", "Archer", "Ninja")]
public string @class = "Warrior";
[Popup ("Human/Local", "Human/Network", "AI/Easy", "AI/Normal", "AI/Hard")]
public string controller;
[Range (0, 100)]
public float health = 100;
[Regex (@"^(?:\d{1,3}\.){3}\d{1,3}$", "Invalid IP address!\nExample: '127.0.0.1'")]
public string serverAddress = "192.168.0.1";
[Compact]
public Vector3 forward = Vector3.forward;
[Compact]
public Vector3 target = new Vector3 (100, 200, 300);
public ScaledCurve range;
public ScaledCurve falloff;
[Angle]
public float turnRate = (Mathf.PI / 3) * 2;
}
public class RegexAttribute : PropertyAttribute {
public readonly string pattern;
public readonly string helpMessage;
public RegexAttribute (string pattern, string helpMessage) {
this.pattern = pattern;
this.helpMessage = helpMessage;
}
}
using UnityEngine;
public class RegexExample : MonoBehaviour {
[Regex (@"^(?:\d{1,3}\.){3}\d{1,3}$", "Invalid IP address!\nExample: '127.0.0.1'")]
public string serverAddress = "192.168.0.1";
}
using UnityEditor;
using UnityEngine;
using System.Text.RegularExpressions;
[CustomPropertyDrawer (typeof (RegexAttribute))]
public class RegexDrawer : PropertyDrawer {
// These constants describe the height of the help box and the text field.
const int helpHeight = 30;
const int textHeight = 16;
// Provide easy access to the RegexAttribute for reading information from it.
RegexAttribute regexAttribute { get { return ((RegexAttribute)attribute); } }
// Here you must define the height of your property drawer. Called by Unity.
public override float GetPropertyHeight (SerializedProperty prop,
GUIContent label) {
if (IsValid (prop))
return base.GetPropertyHeight (prop, label);
else
return base.GetPropertyHeight (prop, label) + helpHeight;
}
// Here you can define the GUI for your property drawer. Called by Unity.
public override void OnGUI (Rect position,
SerializedProperty prop,
GUIContent label) {
// Adjust height of the text field
Rect textFieldPosition = position;
textFieldPosition.height = textHeight;
DrawTextField (textFieldPosition, prop, label);
// Adjust the help box position to appear indented underneath the text field.
Rect helpPosition = EditorGUI.IndentedRect (position);
helpPosition.y += textHeight;
helpPosition.height = helpHeight;
DrawHelpBox (helpPosition, prop);
}
void DrawTextField (Rect position, SerializedProperty prop, GUIContent label) {
// Draw the text field control GUI.
EditorGUI.BeginChangeCheck ();
string value = EditorGUI.TextField (position, label, prop.stringValue);
if (EditorGUI.EndChangeCheck ())
prop.stringValue = value;
}
void DrawHelpBox (Rect position, SerializedProperty prop) {
// No need for a help box if the pattern is valid.
if (IsValid (prop))
return;
EditorGUI.HelpBox (position, regexAttribute.helpMessage, MessageType.Error);
}
// Test if the propertys string value matches the regex pattern.
bool IsValid (SerializedProperty prop) {
return Regex.IsMatch (prop.stringValue, regexAttribute.pattern);
}
}
// Custom serializable class
[System.Serializable]
public class ScaledCurve {
public float scale = 1;
public AnimationCurve curve = AnimationCurve.Linear (0, 0, 1, 1);
}
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer (typeof (ScaledCurve))]
public class ScaledCurveDrawer : PropertyDrawer {
const int curveWidth = 50;
const float min = 0;
const float max = 1;
public override void OnGUI (Rect pos, SerializedProperty prop, GUIContent label) {
SerializedProperty scale = prop.FindPropertyRelative ("scale");
SerializedProperty curve = prop.FindPropertyRelative ("curve");
// Draw scale
EditorGUI.Slider (
new Rect (pos.x, pos.y, pos.width - curveWidth, pos.height),
scale, min, max, label);
// Draw curve
int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField (
new Rect (pos.width - curveWidth, pos.y, curveWidth, pos.height),
curve, GUIContent.none);
EditorGUI.indentLevel = indent;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////