脚本的 Attributes 特性

运行结果

只需要声明变量的时候加上 [RangeIntAttribution(1.0f,100.0f)] 就可以设置成员变量的范围了,并且在 Inspector 面板上如下显示:

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 文件名:Script_04_13
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Script_04_13 : MonoBehaviour
{ // 使用 Range 可以直接创建一个有范围的 Int 或者 Float 值,并且在 Inspector 中显示一个滑动条
// [Range(1, 100)]

// 这里演示自定义 Attribution,为了实验官网的例子,都改成了 float 类型
[RangeIntAttribution(1.0f,100.0f)]
public float rangeFloat;

[RangeIntAttribution(10, 60)]
public int rangeInt;

[RangeIntAttribution('a','z')]
public int rangeInt2;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 文件名:RangeIntAttribution
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
public sealed class RangeIntAttribution : PropertyAttribute
{
// readonly 值类型只可在声明或者构造函数中改变值。
public readonly float minValue;
public readonly float maxValue;

public RangeIntAttribution(float minValue, float maxValue)
{
this.minValue = minValue;
this.maxValue = maxValue;
}
}

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(RangeIntAttribution))]
public sealed class RangeIntDrawer:PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return 90; // 设置面板高度
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// 错的,内含 attribute,不过要向下转型
// PropertyAttribute attribute = new RangeIntAttribution(1, 100);

RangeIntAttribution attribute = this.attribute as RangeIntAttribution;
property.floatValue = Mathf.Clamp(property.floatValue, attribute.minValue, attribute.maxValue);

// 可以使用 positopn 的前三个值,高度要自己估算一下
EditorGUI.HelpBox(new Rect(position.x,position.y,position.width,35), string.Format(
"请输入一个范围从{0}到{1}的整数",attribute.minValue, attribute.maxValue), MessageType.Info);
EditorGUI.PropertyField(new Rect(position.x, position.y + 35, position.width, 20), property, label);

// 再按照官网上的画一个滑动条 https://docs.unity3d.com/ScriptReference/PropertyDrawer.html
if(property.propertyType == SerializedPropertyType.Float)
{
EditorGUI.Slider(new Rect(position.x, position.y + 65, position.width, 20),
property,attribute.minValue, attribute.maxValue);
}
else if (property.propertyType == SerializedPropertyType.Integer)
{
EditorGUI.IntSlider(new Rect(position.x, position.y + 65, position.width, 20), property,
Convert.ToInt32(attribute.minValue), Convert.ToInt32(attribute.maxValue));
}
else
{
EditorGUI.LabelField(new Rect(position.x, position.y + 65, position.width, 20),label.text,
"use Range with int or float");
}
}
}
#endif

RangeAttribute

上述实现了一个有范围的变量,但其实这个功能在 UnityEngine 里面已经有了,可见RangeAttribute,这个主要是要训练一下自定义标签,可以看到其实这个标签调用的应该是 xxxAttribute 类的构造函数。
Unity 里面自带了很多标签,API 可以在 UnityEngine.Attributes 和 UnityEditor.Attributes 中找到,