0%

Unity 编辑器扩展

引子

前提

文章基于Unity 引擎
版本为 v2017.4

Unity 可扩展编辑区域

1. Inspector (属性视图)

2. Menu (菜单)

eg :

1
2
3
4
5
[MenuItem("Duan %g", false, 101)]
public static void Duan()
{

}

3. Menu(右键菜单)

是Menu的一种,需要在Menu之前加上Assets/

1
2
3
4
5
[MenuItem("Assets/导入资源")]
public static void ImportAssets()
{

}

4. ContextMenu 脚本菜单

1
2
3
4
[ContextMenu("ContextMenu Test")]
public void mContextMenu()
{
}

Inspector视图操作

Inspector 对应每个Mono脚本

假设现在有个脚本 Actor.cs,
这个脚本控制角色行为

Inspector 修改方式有两种

  1. 修改其对应的 Actor.cs

  2. 自定义Inspector

  • 创建一个新的Editor类 ActorEditor 继承 Editor
  • 添加[CustomEditor(typeof(Actor))]注解,告诉编辑器这个类是扩展Actor的Inspector。
  • 覆写OnInspectorGUI方法,实现自定义的扩展。

修改 Actor.cs 调整 Inspector

假定我们的 Actor.cs 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
using UnityEngine;

public class Actor : MonoBehaviour {

public int actorId;
public string actorName;
public int weapon1Id, weapon2Id;
public int health;
void Start () {

}

}

第一次修改

  • actorId和actorName 不想要显示,添加 [HideInInspector]
  • weapon1Id,weapon2Id,health 添加 [Header(“XXX”)]
  • health 使用Range显示 [Range(0f, 100f)]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;

public class Actor : MonoBehaviour {
[HideInInspector]
public int actorId;
[HideInInspector]
public string actorName;

[Tooltip("武器ID")]
[Header("左手武器")]
public int weapon1Id;

[Tooltip("武器ID")]
[Header("右手武器")]
public int weapon2Id;
[Range(0f, 100f)]
[Header("血量")]
public int health;
void Start () {
health = 50;
}
}

第二次修改 使用自定义 Inspector

使用自定义会完全抛弃掉Actor中默认行为

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Actor))]
public class ActorEditor : Editor
{
enum WeaponID
{
Sword,
Dagger,
Bow,
MagicBook,
MagicBall,
}

bool showWeapons;
Actor actor;

void OnEnable()
{
actor = (Actor)target;
}

public override void OnInspectorGUI()
{
serializedObject.Update();
//空两行
EditorGUILayout.Space();
EditorGUILayout.Space();

//绘制palyer的基本信息
EditorGUILayout.LabelField("Base Info");

showWeapons = EditorGUILayout.Foldout(showWeapons, "Weapons");
if (showWeapons)
{
WeaponID weapon1ID = (WeaponID)actor.weapon1Id;
weapon1ID = (WeaponID)EditorGUILayout.EnumPopup("Weapon 1 ID", weapon1ID);
actor.weapon1Id = (int)weapon1ID;

WeaponID weapon2ID = (WeaponID)actor.weapon2Id;
weapon2ID = (WeaponID)EditorGUILayout.EnumPopup("Weapon 2 ID", weapon2ID);
actor.weapon2Id = (int)weapon2ID;
}

//空三行
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();

//使用滑块绘制 Player 生命值
actor.health = (int)EditorGUILayout.Slider("Health", actor.health, 0, 100);
//根据生命值设置生命条的背景颜色
if (actor.health < 20)
{
GUI.color = Color.red;
}
else if (actor.health > 80)
{
GUI.color = Color.green;
}
else
{
GUI.color = Color.gray;
}
//指定生命值的宽高
Rect progressRect = GUILayoutUtility.GetRect(50, 50);
//绘制生命条
EditorGUI.ProgressBar(progressRect, actor.health / 100.0f, "Health");


serializedObject.ApplyModifiedProperties();
}

}

Get/Setinspector 中的使用

两种方法

使用自定义Inspector

在Actor加入Speed

get/set 使用起来很方便,但是编辑时在Inspector视图中问题就来了,因为get/set的属性即使是public了.但是在Inspector视图中依然不显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#region get/Set
private int _speed;
public int Speed
{
get
{
return _speed;
}
set
{
Debug.Log("set :" + value);
_speed = value;
}
}
#endregion

_speed 属性设置 [SerializeField]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#region get/Set
[SerializeField]
private int _speed;
public int Speed
{
get
{
return _speed;
}
set
{
if (_speed == value)
return;
Debug.Log("set :" + value);
_speed = value;
}
}
#endregion

可以在 Inspector 中看到
如下

这里还有问题,这里修改speed,并不会调用Get/Set方法

[SerializeField]可以让private 的属性在Inspector视图中显示出来。但是不会调用Get/Set。

使用自定义 Inspector

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Actor))]
public class ActorEditor : Editor
{
enum WeaponID
{
Sword,
Dagger,
Bow,
MagicBook,
MagicBall,
}

bool showWeapons;
Actor actor;

void OnEnable()
{
actor = (Actor)target;
}

public override void OnInspectorGUI()
{
serializedObject.Update();
//空两行
EditorGUILayout.Space();
EditorGUILayout.Space();

//绘制palyer的基本信息
EditorGUILayout.LabelField("Base Info");

showWeapons = EditorGUILayout.Foldout(showWeapons, "Weapons");
if (showWeapons)
{
WeaponID weapon1ID = (WeaponID)actor.weapon1Id;
weapon1ID = (WeaponID)EditorGUILayout.EnumPopup("Weapon 1 ID", weapon1ID);
actor.weapon1Id = (int)weapon1ID;

WeaponID weapon2ID = (WeaponID)actor.weapon2Id;
weapon2ID = (WeaponID)EditorGUILayout.EnumPopup("Weapon 2 ID", weapon2ID);
actor.weapon2Id = (int)weapon2ID;
}

//空三行
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();

//使用滑块绘制 Player 生命值
actor.health = (int)EditorGUILayout.Slider("Health", actor.health, 0, 100);
//根据生命值设置生命条的背景颜色
if (actor.health < 20)
{
GUI.color = Color.red;
}
else if (actor.health > 80)
{
GUI.color = Color.green;
}
else
{
GUI.color = Color.gray;
}
//指定生命值的宽高
Rect progressRect = GUILayoutUtility.GetRect(50, 50);
//绘制生命条
EditorGUI.ProgressBar(progressRect, actor.health / 100.0f, "Health");

int speed = EditorGUILayout.IntField("Speed", actor.Speed);
actor.Speed = speed;

serializedObject.ApplyModifiedProperties();
}

}

使用 自定义属性

待补充 TODO

2. Menu (菜单)

[MenuItem]的基本实现:

  • MenuItem(string path)

参数:

Path—为你的菜单项指定菜单和名字的字符串。Path参数的格式如下:”Root Menu/Sub Menu1/Sub Menu2/Item Name [可选的 快捷键]“ 。

MenuItem 属性的用法例子:

[MenuItem(“Assets/Create/Create Scriptable Object”)]
Path参数的一些额外注意事项:

  • 如果首个词是已经存在的菜单名字(”Assets“, “Window“等),你的菜单项将被添加到这个菜单下(除了Component,稍后详细介绍)
  • 你必须指定一个根菜单和一个菜单项名字
  • 允许在所有菜单名以及菜单项名字中出现空格
  • 可以选择在项名字加空格后的地方指定一个按键来设置快捷键(参考Unity的脚本API的 快捷键)

这个例子代码在GameObject菜单创建了一个菜单项,在选中该项时会在场景中创建一个名为”RedBlue GameObject“的新的游戏对象。

1
2
3
4
5
[MenuItem ("GameObject/Create RedBlue GameObject")]
private static void CreateRedBlueGameObject ()
{
new GameObject ("RedBlue GameObject");
}

特殊类别参考

3. Menu(右键菜单)

同上

4. ContextMenu 脚本菜单

本例中 源码下载

源码下载

欢迎关注我的其它发布渠道