Unity3D仿星露谷物语开发14之Custom Property Attribute
1、目标
创建自定义属性特性,类似于[SerializeField]的属性标签。
当用该自定义属性特性标记变量时,可以在Inspector面板中看到相应的效果。
2、Property类
(1)PropertyAttribute类
propertyAttribute是Unity中用于派生自定义属性特性的基类。
它可以用于为脚本变量创建特性,并于自定义PropertyDrawer类一起,以控制具有该特性的脚本变量在Inspector中显示。
举例1:
[SerializeField]
private int age;
上述代码中SerializeField就是PropertyAttribute类,它没有参数。
举例2:
[Range(0,1)]
public int index = 10;
上述代码中Range就是PropertyAttribute类,它有两个参数。
(2)PropertyDrawer类
PropertyDrawer允许我们控制一个属性的Inspector面板的GUI如何绘制。
常用公共方法:
方法名 | 描述 |
float GetPropertyHeight(SerializedProperty, GUIContent) | 重写此方法以指定此字段的GUI的像素高度。 |
void OnGUI(Rect, SerializedProperty, GUIContent) | 重写此方法,为属性创建自己的基于IMGUI的GUI |
(3)自定义PropertyAttribute的步骤
1)创建自定义属性类
首先,创建一个继承自 PropertyAttribute 的类。例如,创建一个名为 ReadOnlyAttribute 的类:
using UnityEngine;public class ReadOnlyAttribute : PropertyAttribute
{
// 可以添加自定义参数
public ReadOnlyAttribute() { }
}
2)创建自定义属性绘制类
接下来,创建一个继承自 PropertyDrawer 的类,用于定义自定义属性在 Inspector 中的显示方式。例如,创建一个名为 ReadOnlyAttributeDrawer 的类:
using UnityEditor;
using UnityEngine;[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
public class ReadOnlyAttributeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
GUI.enabled = false; // 禁用编辑
EditorGUI.PropertyField(position, property, label);
GUI.enabled = true; // 恢复编辑
}
}
3)使用自定义属性
最后,在需要的脚本中使用自定义属性。例如:
using UnityEngine;public class Test : MonoBehaviour
{
[ReadOnly]
public int myInt = 10;
}
3、创建步骤
(1)创建PropertyAttribute类
在Assets -> Scripts下创建目录命名为Utilities。
并在此目录下再创建子目录命名为Property Drawers。
在此目录下创建脚本命名为ItemCodeDescriptionAttribute.cs
代码如下:
using UnityEngine;public class ItemCodeDescriptionAttribute : PropertyAttribute
{// No values need to be held for the item code description attribute// so the class can be empty
}
因为是无参特性,所以可以不用定义任何内容。
(2)创建PropertyDrawer类
在Assets -> Scripts -> Utilities -> Property Drawers下创建Editor目录。
在此目录下创建脚本ItemCodeDescriptionDrawer.cs
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;[CustomPropertyDrawer(typeof(ItemCodeDescriptionAttribute))]
public class ItemCodeDescriptionDrawer : PropertyDrawer
{public override float GetPropertyHeight(SerializedProperty property, GUIContent label){// Change the returned property height to be double to cater for the additional item code description that we will drawreturn EditorGUI.GetPropertyHeight(property) * 2;}public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){// Using BeginProperty / EndProperty on the parent property means that prefab override logic works on the entire property.EditorGUI.BeginProperty(position, label, property);if (property.propertyType == SerializedPropertyType.Integer) {EditorGUI.BeginChangeCheck(); // Start of check for changed values// Draw item codevar newValue = EditorGUI.IntField(new Rect(position.x, position.y, position.width, position.height / 2), label, property.intValue);// Draw item descriptionEditorGUI.LabelField(new Rect(position.x, position.y + position.height / 2, position.width, position.height / 2), "Item Description", GetItemDescription(property.intValue));// If item code value has changed, then set value to new valueif (EditorGUI.EndChangeCheck()) {property.intValue = newValue;}}EditorGUI.EndProperty();}private string GetItemDescription(int itemCode){SO_ItemList so_ItemList;so_ItemList = AssetDatabase.LoadAssetAtPath("Assets/Scriptable Object Assets/Item/so_ItemList.asset", typeof(SO_ItemList)) as SO_ItemList;List<ItemDetails> itemDetailsList = so_ItemList.itemDetails;ItemDetails itemDetail = itemDetailsList.Find(x => x.itemCode == itemCode);if (itemDetail != null) {return itemDetail.itemDescription;}else{return "";}}
}
(3)使用PropertyAttribute属性
在Item.cs文件中,给_itemCode变量增加[ItemCodeDescription]。
此时再点击Hierarchy -> Items中的道具,可以看到Inspector的Item组件中出现了Item Description属性。