引子 前提 文章基于Unity 引擎 版本为 v2017.4
Unity 可扩展编辑区域 1. Inspector (属性视图)
eg :
1 2 3 4 5 [MenuItem("Duan %g", false, 101)] public static void Duan() { }
是Menu的一种,需要在Menu之前加上Assets/
1 2 3 4 5 [MenuItem("Assets/导入资源")] public static void ImportAssets() { }
1 2 3 4 [ContextMenu("ContextMenu Test")] public void mContextMenu() { }
Inspector 视图操作Inspector 对应每个Mono 脚本
假设现在有个脚本 Actor.cs , 这个脚本控制角色行为
Inspector 修改方式有两种
修改其对应的 Actor.cs
自定义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/Set 在 inspector 中的使用两种方法
使用自定义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
[MenuItem ]的基本实现:
参数:
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"); }
特殊类别参考
同上
略
本例中 源码下载 源码下载