码迷,mamicode.com
首页 > 编程语言 > 详细

Unity定制,将属性暴露在Inspector面板上

时间:2015-07-12 12:54:55      阅读:531      评论:0      收藏:0      [点我收藏+]

标签:unity3d   unity   ugui   

孙广东   2015、7、12

Unity的很多编辑器功能都是通过特性Attribute实现。

那么我们要自己扩展Inspector也是要自己写Attribute。


先说说为什么要这样做?

为了编写面向对象程序,封装特性 更优雅。下面的脚本使 属性 (即有 getter/setter 的成员) 的内容可以在Unity的Inspector上显示。
这样就可以保密类的 字段,并限制所有的外部访问,只能通过 属性 访问,


看看代码吧!

using System;
 
[AttributeUsage(AttributeTargets.Property)] public class ExposePropertyAttribute : Attribute {}

在   "Assets/Editor"  的脚本

using UnityEditor;
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
 
public static class ExposeProperties
{
	public static void Expose(PropertyField[] properties)
	{
		var emptyOptions = new GUILayoutOption[0];
		EditorGUILayout.BeginVertical(emptyOptions);
		foreach (PropertyField field in properties)
		{
			EditorGUILayout.BeginHorizontal(emptyOptions);
			if (field.Type == SerializedPropertyType.Integer)
			{
				var oldValue = (int)field.GetValue();
				var newValue = EditorGUILayout.IntField(field.Name, oldValue, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			else if (field.Type == SerializedPropertyType.Float)
			{
				var oldValue = (float)field.GetValue();
				var newValue = EditorGUILayout.FloatField(field.Name, oldValue, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			else if (field.Type == SerializedPropertyType.Boolean)
			{
				var oldValue = (bool)field.GetValue();
				var newValue = EditorGUILayout.Toggle(field.Name, oldValue, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			else if (field.Type == SerializedPropertyType.String)
			{
				var oldValue = (string)field.GetValue();
				var newValue = EditorGUILayout.TextField(field.Name, oldValue, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			else if (field.Type == SerializedPropertyType.Vector2)
			{
				var oldValue = (Vector2)field.GetValue();
				var newValue = EditorGUILayout.Vector2Field(field.Name, oldValue, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			else if (field.Type == SerializedPropertyType.Vector3)
			{
				var oldValue = (Vector3)field.GetValue();
				var newValue = EditorGUILayout.Vector3Field(field.Name, oldValue, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			else if (field.Type == SerializedPropertyType.Enum)
			{
				var oldValue = (Enum)field.GetValue();
				var newValue = EditorGUILayout.EnumPopup(field.Name, oldValue, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			else if (field.Type == SerializedPropertyType.ObjectReference)
			{
				UnityEngine.Object oldValue = (UnityEngine.Object)field.GetValue();
				UnityEngine.Object newValue = EditorGUILayout.ObjectField(field.Name, oldValue, field.Info.PropertyType, emptyOptions);
				if (oldValue != newValue)
					field.SetValue(newValue);
			}
			EditorGUILayout.EndHorizontal();
		}
		EditorGUILayout.EndVertical();
	}
 
	public static PropertyField[] GetProperties(object obj)
	{
		var fields = new List<PropertyField>();
 
		PropertyInfo[] infos = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
 
		foreach (PropertyInfo info in infos)
		{
			if (!(info.CanRead && info.CanWrite))
				continue;
 
			object[] attributes = info.GetCustomAttributes(true);
 
			bool isExposed = false;
			foreach (object o in attributes)
				if (o.GetType() == typeof(ExposePropertyAttribute))
			{
				isExposed = true;
				break;
			}
			if (!isExposed)
				continue;
 
			var type = SerializedPropertyType.Integer;
			if (PropertyField.GetPropertyType(info, out type))
			{
				var field = new PropertyField(obj, info, type);
				fields.Add(field);
			}
		}
 
		return fields.ToArray();
	}
}
 
public class PropertyField
{
	object obj;
	PropertyInfo info;
	SerializedPropertyType type;
 
	MethodInfo getter;
	MethodInfo setter;
 
	public PropertyInfo Info
	{
		get { return info; }
	}
 
	public SerializedPropertyType Type
	{
		get { return type; }
	}
 
	public String Name
	{
		get { return ObjectNames.NicifyVariableName(info.Name); }
	}
 
	public PropertyField(object obj, PropertyInfo info, SerializedPropertyType type)
	{
		this.obj = obj;
		this.info = info;
		this.type = type;
 
		getter = this.info.GetGetMethod();
		setter = this.info.GetSetMethod();
	}
 
	public object GetValue() { return getter.Invoke(obj, null); }
	public void SetValue(object value) { setter.Invoke(obj, new[] {value}); }
 
	public static bool GetPropertyType(PropertyInfo info, out SerializedPropertyType propertyType)
	{
		Type type = info.PropertyType;
		propertyType = SerializedPropertyType.Generic;
		if (type == typeof(int))
			propertyType = SerializedPropertyType.Integer;
		else if (type == typeof(float))
			propertyType = SerializedPropertyType.Float;
		else if (type == typeof(bool))
			propertyType = SerializedPropertyType.Boolean;
		else if (type == typeof(string))
			propertyType = SerializedPropertyType.String;
		else if (type == typeof(Vector2))
			propertyType = SerializedPropertyType.Vector2;
		else if (type == typeof(Vector3))
			propertyType = SerializedPropertyType.Vector3;
		else if (type.IsEnum)
			propertyType = SerializedPropertyType.Enum;
		else if (typeof(MonoBehaviour).IsAssignableFrom(type))
			propertyType = SerializedPropertyType.ObjectReference;
		return propertyType != SerializedPropertyType.Generic;
	}
}


using UnityEngine;
 
public class ExposableMonobehaviour : MonoBehaviour {}

在 "Assets/Editor" 文件夹下的脚本

using UnityEditor;
using UnityEngine;
using System.Collections;
 
[CustomEditor(typeof(ExposableMonoBehaviour), true)] 
public class ExposableMonobehaviourEditor : Editor
{
	ExposableMonoBehaviour m_Instance;
	PropertyField[] m_fields;
 
	public virtual void OnEnable()
	{
		m_Instance = target as ExposableMonoBehaviour;
		m_fields = ExposeProperties.GetProperties(m_Instance);
	}
 
	public override void OnInspectorGUI()
	{
		if (m_Instance == null)
			return;
		this.DrawDefaultInspector();
		ExposeProperties.Expose(m_fields);
	}
}

【注】
这将允许类从 ExposableMonobehaviour 继承,将增强暴露 setter 和 getter 方法。没有明显的性能问题。
你可能已经看到上面的代码中,只有以下类型目前是暴露的 (尽管是容易实现其他的类型):

- Integer
- Float
- Boolean
- String
- Vector2
- Vector3
- Enum
- Object Reference (Monobehavior)

【使用:】
现在创建一个类扩展 ExposableMonobehaviour,并使用属性。属性必须有 getter 和 setter 访问器和 [ExposeProperty] 特性设置,否则该属性将不会被显示。
当你play时为了要保存属性值,您必须添加 [SerializeField] 到属性的字段。不幸的是,这把字段 暴露了到编辑器,因此您必须显式隐藏,使用 [HideInInspector]。

示例:随便挂在一个对象上

using UnityEngine;
 
public class MyType : ExposableMonoBehaviour
{
	[HideInInspector, SerializeField] int m_SomeInt;
	[HideInInspector, SerializeField] float m_SomeFloat;
	[HideInInspector, SerializeField] bool m_SomeBool;
	[HideInInspector, SerializeField] string m_Etc;
        [HideInInspector, SerializeField] MonoBehaviour m_Obj;
 
	[ExposeProperty] public int SomeInt
	{
		get { return m_SomeInt; }
		set { m_SomeInt = value; }
	}
 
	[ExposeProperty] public float SomeFloat
	{
		get { return m_SomeFloat; }
		set { m_SomeFloat = value; }
	}
 
	[ExposeProperty] public bool SomeBool
	{
		get { return m_SomeBool; }
		set { m_SomeBool = value; }
	}
 
	[ExposeProperty] public string SomeString
	{
		get { return m_Etc; }
		set { m_Etc = value; }
	}
 
        [ExposeProperty] public MonoBehaviour SomeScript
	{
		get { return m_Obj; }
		set { m_Obj = value; }
	}
}

技术分享

技术分享

技术分享


版权声明:本文为博主原创文章,未经博主允许不得转载。

Unity定制,将属性暴露在Inspector面板上

标签:unity3d   unity   ugui   

原文地址:http://blog.csdn.net/u010019717/article/details/46848321

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!