Edtior文件位置灵活,可以作为多个目录的子文件夹存在
按功能划分不同的Editor目录
Project拓展
public class ProjectEditor
{
//1.Project下的右键窗口菜单项,与具体文件无关,右键就行
[MenuItem("Assets/My Right Tools/PrintName",false,2)] //2排序位置,越小越往上
static void MyRightTools()
{
Debug.Log(Selection.activeObject.name);
}
//2.Project右键窗口创建基元对象,创建在Hierarchy中,Project里是不能有对象的,只有有预制体。
[MenuItem("Assets/My Right Tools/CreateCube",false,1)]
static void CreateCube()
{
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
//3. 选中的资源拓展
[InitializeOnLoadMethod] //c#每次编译完成调用一次
static void InitializeOnLoadMethod()
{
EditorApplication.projectWindowItemOnGUI = delegate(string guid,Rect selectionRect) //利用委托用ongui的事件来重新绘制project里面的item
{
if(Selection.activeObject&&guid==AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(Selection.activeObject))) //在选中物体的时候
{
float width = 50f;
selectionRect.x += (selectionRect.width - width); //确保最右端一样
selectionRect.y += 2f; //起点增加是往上走,y,不射h默认占满selection.activeobject。
selectionRect.width = width;
GUI.color = Color.red;
//开始图形的绘制
if (GUI.Button(selectionRect, "click"))
{
Debug.LogFormat("click:{0}", Selection.activeObject.name); //格式化debug
}
//颜色回溯
GUI.color = Color.white;
}
}; //匿名委托
}
}
Hierarchy拓展
public class HierarchyEditor
{
//1.Hierarchy面板下Create菜单增加使用GameObject/路径
[MenuItem("GameObject/My Create/Create Cube",false,1)]
static void MyCreateCube()
{
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
[MenuItem("GameObject/My Create/Create Cube2", false, 12)] //每10个空位是一条分割线,所以n+11就会有一条分隔符了
static void MyCreateCube2()
{
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
//2. 选中的资源拓展
[InitializeOnLoadMethod] //c#每次编译完成调用一次
static void InitializeOnLoadMethod()
{
EditorApplication.hierarchyWindowItemOnGUI = delegate (int instanceId, Rect selectionRect) //利用委托用ongui的事件来重新绘制project里面的item
{
if (Selection.activeObject && instanceId == Selection.activeObject.GetInstanceID()) //在选中物体的时候
{
float width = 50f;
float height = 20f;
selectionRect.x += (selectionRect.width - width); //右对齐
selectionRect.width = width;
selectionRect.height = height;//下无法对齐,因为hierarchy下的对象大小都一样,所以这里用固定高度
GUI.color = Color.red;
//开始图形的绘制
if (GUI.Button(selectionRect,"click"))
{
Debug.LogFormat("click:{0}", Selection.activeObject.name); //格式化debug
}
//颜色回溯
GUI.color = Color.white;
}
}; //匿名委托
}
[MenuItem("My PopUp/Test1")]
static void Test1()
{
Debug.LogFormat("My:{0}", "Test1");
}
[MenuItem("My PopUp/Test2")]
static void Test2()
{
Debug.Log("Test2");
}
//3.右键的重写菜单
[InitializeOnLoadMethod]
static void StartinitializeOnLoadMethod()
{
EditorApplication.hierarchyWindowItemOnGUI += delegate (int instanceID, Rect selectionRect) //这句话保证右键一定是要点击在对象上才会触发,空白右键无对象物体不触发
{
//右键点击且拾起,
if (Event.current != null && selectionRect.Contains(Event.current.mousePosition) && Event.current.button == 1 && Event.current.type <= EventType.MouseUp)
{
GameObject activeObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject; //根据id获得游戏对象
if (activeObject)
{
EditorUtility.DisplayPopupMenu(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 0, 0), "My PopUp", null); //核心,绘制新的菜单
Event.current.Use();//弃用原来的方法,使用新的菜单
}
}
};
}
//4.重写自带右键菜单的行为
//自动勾选RaycastTarget==false
[MenuItem("GameObject/UI/Image")]
static void CreateImage()
{
if(Selection.activeTransform)
{
if(Selection.activeTransform.GetComponentInParent<Canvas>()) //一定要在canvas下
{
Image image = new GameObject("Image").AddComponent<Image>();
image.raycastTarget = false; //核心
image.transform.SetParent(Selection.activeTransform, false); //和父亲坐标一起
//设置选中状态
Selection.activeTransform = image.transform;
}
}
}
}
Inspector拓展
//1.拓展原生组件,只能加在上方或者下方
[CustomEditor(typeof(Camera))] //只能针对于类使用,相当于一个组件一个类了
public class CameraEditor:Editor //保证Override, OnInspectorGUI
{
public override void OnInspectorGUI()
{
if(GUILayout.Button("拓展按钮"))
{ }
base.OnInspectorGUI();
}
}
//2.拓展继承组件,系统组件已经在unity内置中重写了绘制方法,且该方法已为私有,外界无法访问原生的,只能访问重写之后的
//解决:反射访问私有的真正原生的绘制方法
[CustomEditor(typeof(Transform))]
public class TransformEditor:Editor
{
private Editor _Editor;
private void OnEnable() //只有这个组件脚本有用就会被执行
{
//一个dll包含多个命名空间
_Editor = Editor.CreateEditor(target/*正在被检视的物体*/, Assembly.GetAssembly(typeof(Editor)/*Editor dll下有一个UnityEditor命名空间的transformInspector类型的类*/).GetType("UnityEditor.TransformInspector",true/*出错了反射会抛出错误*/));
}
public override void OnInspectorGUI()
{
if(GUILayout.Button("拓展按钮"))
{
}
//base.OnInspectorGUI(); 重写后的不好看
_Editor.OnInspectorGUI();
}
}
//3.通过highFlag可以让某个对象或者某个组件在属性面板上不可编辑
public class NotEditor
{
[MenuItem("GameObject/3D Object/Lock/LockTransform",false,0)]
static void Lock()
{
if(Selection.gameObjects!=null) //选择了物体就要把一群物体对应的组件禁用
{
foreach (var item in Selection.gameObjects)
{
item.transform.hideFlags = HideFlags.NotEditable;
}
}
}
[MenuItem("GameObject/3D Object/Lock/UnLockTransform", false, 0)]
static void UnLock()
{
if (Selection.gameObjects != null) //选择了物体就要把一群物体对应的组件禁用
{
foreach (var item in Selection.gameObjects)
{
item.transform.hideFlags = HideFlags.None; //取消标记
}
}
}
}
//4.Context菜单,属性面板上右键组件的菜单修改
public class ContextEditor:MonoBehaviour //使用Unity组件不要忘了MonoBehavior
{
//新增
[MenuItem("CONTEXT/Transform/New Context1")]
public static void NewContext1(MenuCommand command) //右键组件的组件上下文
{
Debug.Log(command.context.name);
}
[MenuItem("CONTEXT/Transform/New Context2")] //默认新生成的priorId减少,减少在下面
public static void NewContext2(MenuCommand command) //右键组件的组件上下文
{
Debug.Log(command.context.name);
}
//如果组件是脚本的话还可以把command.context强制转换成对应的脚本类型,然后修改公共成员
//略
//如果名字和系统的菜单项名称一样,则会覆盖原来的内容
[ContextMenu("Remove Component")]
void RemoveCompoent()
{
Debug.Log("RemoveComponent");
EditorApplication.delayCall = delegate ()
{
DestroyImmediate(this);
};
}
}
Scene拓展
#if UNITY_EDITOR
[CustomEditor(typeof(Camera))]
public class EditorSceneUI:Editor //OnSceneGUI为Editor的回调函数
{
//1.辅助UI,针对特定的选中物体,组件
private void OnSceneGUI()
{
Camera camera = target as Camera;
if (camera != null)
{
Handles.color = Color.red;
Handles.Label(camera.transform.position, camera.transform.position.ToString()); //Handles手段的绘制要放在BeginGUI之外,而GUI的绘制要放在里面
Handles.BeginGUI();
GUI.backgroundColor = Color.red;
if (GUILayout.Button("click", GUILayout.Width(200f)))
{
Debug.LogFormat("click = {0}", camera.name);
}
GUILayout.Label("label");
Handles.EndGUI();
}
}
}
#endif
MenuItem
//MenuItem
//1.拓展全局自定义快捷键
public class MenuItemClass {
[MenuItem("Assets/HotKey %#d",false,-1)]
static void HotKey()
{
Debug.Log("ctrl+shift+d");
}
}
EditorGUI
与GUI使用几乎一致,多用于编辑器开发,脚本中声明的public可序列化变量可以通过EditorGUI对其进行绘制。EditorGUILayout
//EditorGUI
#if UNITY_EDITOR
//1.常用EditorGUI
[CustomEditor(typeof(myScripts))]
public class EditorGUITest : Editor
{
private bool _EnableToggle;
public override void OnInspectorGUI()
{
//获取脚本对象
myScripts script = target as myScripts;
script.myName = EditorGUILayout.TextField("text", script.myName); //一个string字段就是一个text
script.myId = EditorGUILayout.IntField("int", script.myId); //int - int
script.prefab = EditorGUILayout.ObjectField("GameObject", script.prefab, typeof(GameObject), true) as GameObject; //prefab-GameObject
EditorGUILayout.BeginHorizontal();
GUILayout.Button("1");
GUILayout.Button("2");
EditorGUILayout.EndHorizontal();
script.myEnum = (myScripts.MyEnum)EditorGUILayout.EnumPopup("haha", script.myEnum);
_EnableToggle = EditorGUILayout.BeginToggleGroup("我的TogGrp:", _EnableToggle);
script.Tog1 = EditorGUILayout.Toggle("tog1:", script.Tog1);
script.toggle2 = EditorGUILayout.Toggle("toggle2:", script.toggle2);
EditorGUILayout.EndToggleGroup();
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeAge"), true); //以默认的样子绘制可序列化字段,一定要是加seralizefile特性的,否则找不到,会出错
EditorGUILayout.HelpBox("这是一个帮助提示框", MessageType.Info);
serializedObject.ApplyModifiedProperties(); //要数据保存才可以修改数据
}
}
//2.EditorGUI样式(EditorStyles)
public class EditorStylesTest:EditorWindow
{
//获得所有样式
static List<GUIStyle> styles = null;
static List<string> _IconNames = null;
static Texture2D[] _Icons = null;
//所有图标
[MenuItem("Window/Show All Styles")]
static void GetAllStyles()
{
_IconNames = new List<string>();
_Icons = Resources.FindObjectsOfTypeAll<Texture2D>();
for (int i = 0; i < _Icons.Length; i++)
{
Debug.unityLogger.logEnabled = false;//为了让他不报错,其他非unity内置资源提取不出来会报错
GUIContent content = EditorGUIUtility.IconContent(_Icons[i].name); //不是unity内置的资源提取出来的content就会为null
Debug.unityLogger.logEnabled = true;
if(content!=null&&content.image!=null)
{
_IconNames.Add(_Icons[i].name);
}
}
EditorStylesTest window = (EditorStylesTest)EditorWindow.GetWindow<EditorStylesTest>("styles");
styles = new List<GUIStyle>();
foreach (var item in typeof(EditorStyles).GetProperties(BindingFlags.Static| BindingFlags.Public| BindingFlags.NonPublic)) //有些样式属性可能是私有的
{
object o = item.GetValue(null, null);
if(o.GetType()==typeof(GUIStyle))
{
styles.Add(o as GUIStyle);
}
}
window.Show();
}
Vector2 scrollPos;
Vector2 sp2;
//绘制
private void OnGUI()
{
//所有风格
scrollPos = EditorGUILayout.BeginScrollView(scrollPos,false,false,GUILayout.Height(400)); //可选参数里面控制ScrollView的范围
for (int i = 0; i < styles.Count; i++)
{
GUILayout.Label($"styles{i}:{styles[i].name}", styles[i]);
}
EditorGUILayout.EndScrollView();
EditorGUILayout.Separator();
//所有图标
sp2 = EditorGUILayout.BeginScrollView(sp2, false, true);
int m = (int)(position.width/50);
for (int i = 0; i <_IconNames.Count; i++)
{
GUILayout.BeginHorizontal();
for (int j = 0; j < m; j++)
{
int index = i + j; //后面i增加了导致index可能大于length
if(index<_IconNames.Count)
GUILayout.Button(EditorGUIUtility.IconContent(_IconNames[index]), GUILayout.Width(50), GUILayout.Height(30)); //EditorGUIUtility.IconContent根据名字提取unity内置的资源
}
GUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
}
}
#endif
所有EditorGUI可以使用的样式
EditorWindow
//EditorWindow
public class EditorWindowTest:EditorWindow,IHasCustomMenu //继承IHasCustomMenu接口可以扩展window编辑窗口的右上角
{
private float _scrollFloat;
[MenuItem("Window/Open My Window")]
//初始化打开一个窗口(根据一个窗口类)
static void Init()
{
EditorWindowTest window = (EditorWindowTest)EditorWindow.GetWindow(typeof(EditorWindowTest));
window.Show();
}
//右上角按钮点击出来的
public void AddItemsToMenu(GenericMenu menu)
{
menu.AddItem(new GUIContent("test1"), true, () => //默认勾选true
{
Debug.Log("test1");
});
menu.AddSeparator("Test/");
menu.AddDisabledItem(new GUIContent("Disable"));
}
private void OnGUI()
{
//绘制在这里绘制
GUILayout.Label("hello world!",EditorStyles.boldLabel);
_scrollFloat = EditorGUILayout.Slider("slider", _scrollFloat, 0, 1);
}
}