赞
踩
PropertyAttribute
自定义特性的基类,可以使用它为脚本创建自定义属性。
PropertyAttribute 与 PropertyDrawer一起使用,可以控制具有该特性的脚本在Inspector中的显示方式。
PropertyDrawer
借助属性绘制器,可以通过使用脚本上的特性或通过控制特定 Serializable
类的外观来自定义 Inspector 窗口中某些控件的外观。
属性绘制器有两种用途:
属性绘制器类应放在编辑器脚本中,该脚本位于称为 Editor 的文件夹内。
- using System;
- using UnityEngine;
-
- enum IngredientUnit { Spoon, Cup, Bowl, Piece }
-
- // 自定义 Serializable 类
- [Serializable]
- public class Ingredient
- {
- public string name;
- public int amount = 1;
- public IngredientUnit unit;
- }
- using UnityEngine;
-
- public class Recipe : MonoBehaviour
- {
- public Ingredient ingredient;
- public Ingredient[] ingredients;
- }
可以使用自定义属性绘制器来更改 Inspector 中 Ingredient 类的每个外观。比较不带有和带有自定义属性绘制器的 Inspector 中 Ingredient 属性的外观:
不带有(左)和带有(右)自定义属性绘制器的 Inspector 中的类。
可以使用 CustomPropertyDrawer 属性将属性绘制器附加到 Serializable 类,然后传入属性绘制器所针对的 Serializable 类的类型。
- using UnityEditor;
- using UnityEngine;
-
- // IngredientDrawer
- [CustomPropertyDrawer(typeof(Ingredient))]
- public class IngredientDrawer : PropertyDrawer
- {
- // 在给定的矩形内绘制属性
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
- {
- // 在父属性上使用 BeginProperty/EndProperty 意味着
- // 预制件重写逻辑作用于整个属性。
- EditorGUI.BeginProperty(position, label, property);
-
- //绘制标签
- position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
-
- // 不要让子字段缩进
- var indent = EditorGUI.indentLevel;
- EditorGUI.indentLevel = 0;
-
- // 计算矩形
- var amountRect = new Rect(position.x, position.y, 30, position.height);
- var unitRect = new Rect(position.x + 35, position.y, 50, position.height);
- var nameRect = new Rect(position.x + 90, position.y, position.width - 90, position.height);
-
- // 绘制字段 - 将 GUIContent.none 传入每个字段,从而可以不使用标签来绘制字段
- EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("amount"), GUIContent.none);
- EditorGUI.PropertyField(unitRect, property.FindPropertyRelative("unit"), GUIContent.none);
- EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("name"), GUIContent.none);
-
- // 将缩进恢复原样
- EditorGUI.indentLevel = indent;
-
- EditorGUI.EndProperty();
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
PropertyDrawer 的另一用途是改变脚本中具有自定义 PropertyAttribute 的成员的外观。 假如您要将脚本中的浮点数或整数限制在特定范围内,并在 Inspector 中将其显示为滑动条。 那么,您可以使用内置的 PropertyAttribute(名为 RangeAttribute)来执行此操作:
- using UnityEngine;
- using System.Collections;
-
- public class ExampleClass : MonoBehaviour
- {
- // 在 Inspector 中将此浮点数显示为 0 到 10 之间的滑动条
- [Range(0.0F, 10.0F)]
- public float myFloat = 0.0F;
- }
您还可以创建自己的 PropertyAttribute。我们将以 RangeAttribute 的代码为例。 该特性必须扩展 PropertyAttribute 类。如果需要,属性可以使用参数并将它们存储为公共成员变量。
- using UnityEngine;
-
- public class RangeAttribute : PropertyAttribute
- {
- public float min;
- public float max;
-
- public RangeAttribute(float min, float max)
- {
- this.min = min;
- this.max = max;
- }
- }
拥有该特性后,需要创建一个 PropertyDrawer 来绘制具有该特性的属性。 绘制器必须扩展 PropertyDrawer 类,且必须具有 CustomPropertyDrawer 特性来说明绘制器所对应的特性。
- using UnityEngine;
- using UnityEditor;
-
- [CustomPropertyDrawer(typeof(RangeAttribute))]
- public class RangeDrawer : PropertyDrawer
- {
- // 在给定的矩形内绘制属性
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
- {
- // 首先获取该特性,因为它包含滑动条的范围
- RangeAttribute range = attribute as RangeAttribute;
-
- // 现在根据属性是浮点值还是整数来确定将属性绘制为 Slider 还是 IntSlider。
- if (property.propertyType == SerializedPropertyType.Float)
- EditorGUI.Slider(position, property, range.min, range.max, label);
- else if (property.propertyType == SerializedPropertyType.Integer)
- EditorGUI.IntSlider(position, property, Convert.ToInt32(range.min), Convert.ToInt32(range.max), label);
- else
- EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
请注意,出于性能原因,EditorGUILayout 函数不能用于属性绘制器。
- using UnityEngine;
-
- public class ItemDescriptionAttribute : PropertyAttribute
- {
-
- }
- using UnityEngine;
- using UnityEditor;
-
- [CustomPropertyDrawer(typeof(ItemDescriptionAttribute))]
- public class ItemDescriptionDrawer : PropertyDrawer
- {
- public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
- {
- return base.GetPropertyHeight(property, label) * 2; // 原来高度的两倍,显示两行
- }
-
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
- {
- EditorGUI.BeginProperty(position, label, property);
-
- if(property.propertyType == SerializedPropertyType.Integer)
- {
- EditorGUI.BeginChangeCheck();
-
- int id = EditorGUI.IntField(new Rect(position.x, position.y, position.width, position.height / 2), label, property.intValue);
-
- EditorGUI.LabelField(new Rect(position.x, position.y + position.height / 2, position.width, position.height / 2), "ItemDescription", GetItemDescription(id));
-
- if (EditorGUI.EndChangeCheck())
- {
- property.intValue = id;
- }
-
- ItemConfig cfg = ConfigMgr.Instance.GetItemConfigById(id);
- SetSprite(cfg);
- }
-
- EditorGUI.EndProperty();
- }
-
- private string GetItemDescription(int id)
- {
- // 根据id读取对应配置描述
- ItemConfig config = ConfigMgr.Instance.GetItemConfigById(id);
- if(config != null)
- {
- return config.name;
- }
- return "物品描述";
- }
-
- private void SetSprite(cfg)
- {
- // 根据配置,更换对应的sprite图片
- // 获取unity当前正选择的gameobject,并获取它的精灵组件
- SpriteRenderer spriteRenderer = Selection.activeGameObject.GetComponent<SpriteRenderer>();
- //Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/Art/Textures/kongLong.jpeg");
- Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(cfg.sprite);
- spriteRenderer.sprite = sprite;
- // Debug.Log("Test-" + Selection.activeGameObject.name);
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
参考资料:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。