Unity编辑器扩展

目录

    • 编辑器常见修饰符
    • 菜单栏扩展方法
    • 打开文件
    • 增加类或者对象在Inspector窗口的功能(按钮,说明等)
    • 脚本编译完成后回调
    • (修改后)资源重新加载后回调
    • 编辑模式运行回调
    • ContextMenu及ContextMenuItem
    • Scane视图添加自定义菜单
    • ScriptableWizard
    • 参考:

近来无事,巩固一下unity编辑器扩展相关知识,一顿胡乱折腾,将四处网罗的东西东拼西凑写一写,打发时间

编辑器常见修饰符

  • [SerializeField] 序列化,将私有属性暴露在属性面板,可编辑
  • [HideInInspector] 隐藏属性,修饰属性,隐藏暴露在属性面板的属性
  • [NonSerialized] 不可序列化,修饰属性,且在Inspector面板上隐藏
  • [Header(“描述”)] 标题栏,修饰属性,在属性面板显示
  • [Tooltip(“描述”)] 提示字段,修饰属性,鼠标指向的时候显示
  • [Space(5)] 间隔距离,修饰属性
  • [Range(min,max)] 限制范围,修饰值类型数据
  • [InitializeOnLoadMethod] 加载时调用, 修饰方法,方法必须是static方法
  • [InitializeOnLoad] 加载时调用, 修饰类,
  • [AddComponentMenu(“路径”)] 修饰类,可以在指定的路径的直接添加该类
  • [ContextMenuItem(“标签名”,“方法名”)] 修饰属性,将属性设置为该标签时,执行方法,类需继承自MonoBehaviour
  • [ContextItem(“标签名”)] 修饰方法,在挂载脚本(类级别)设置该标签时,执行方法,类需继承自MonoBehaviour
  • [MenuItem(“目录路径”) 特殊的路径,修饰方法:
    1. GameObject/ 菜单出现在GameObject节点下
    2. Assets/ 菜单出现在Assets节点下(Project面板下右键弹出的面板内容和Assets节点展开的是一致的)
    3. MenuItem(“CONTEXT/组件名/XXX”) 为某个具体组件的Inspector上下文菜单增加内容。打开方式为右键组件或者左键组件最右边的“齿轮”按钮,需要注意的是Inspector上下文添加菜单不支持多重层次
  • EditorApplication.ExecuteMenuItem(“XX/XX/XX”)

菜单栏扩展方法

  • 必须是静态方法
  • 使用如下标签
[MenuItem("路径/方法名 快捷键符号"{bool:是否可用}{int:层级})]
参数1: 显示位置, string类型, 在菜单栏显示方法,
	   快捷键符号: 
	   		@ Shift     	#			用于组合键
	   		@ Ctrl    		%			用于组合键
	   		@ Alt    		&			用于组合键
	   		@ 英文字母    	_字母		单独使用需要加上'_',也可以与上面组合使用
参数2: 是否显示, bool类型, 可选参数, 默认为false, 按钮可用, true不可用
参数3: 优先层级, int类型, 可选参数,0开始, 越小位置越靠上
  • 示例
using UnityEditor;
using UnityEngine;

public class UnityToolsEditor
{
	[MenuItem("Tools/测试方法1 _a")]
	public static void Test1()
	{
		Debug.Log("Tools/测试方法1");
	}

	[MenuItem("Tools/测试方法2 _B", false)]
	public static void Test2()
	{
		Debug.Log("Tools/测试方法2");
	}

	[MenuItem("Tools/测试方法3 &A", false, 4)]
	public static void Test3()
	{
		Debug.Log("Tools/测试方法3");
	}

	[MenuItem("Tools/测试方法4 %a", false, 3)]
	public static void Test4()
	{
		//说明:测试方法4会在测试方法3的上面
		Debug.Log("Tools/测试方法4");
	}
	
	// 设置可用状态, 执行后不可用, 测试方法5和测试方法6设置
	private static int _CheckedTest5_6 = 5;

	[MenuItem("Tools/测试方法5 #A")]
	public static void Test5()
	{
		//执行后该方法不可用
		_CheckedTest5_6 = 6;
		Debug.Log("Tools/测试方法5");
	}
	[MenuItem("Tools/测试方法5", validate = true)]
	public static bool Test5Validate()
	{
		//说明:检测并设置Test5是否可用,需配合Test5使用,单独不显示
		return _CheckedTest5_6 == 5;
	}

	[MenuItem("Tools/测试方法6")]
	public static void Test6()
	{
		//执行后该方法不可用
		_CheckedTest5_6 = 5;
		Debug.Log("Tools/测试方法6");
	}
	[MenuItem("Tools/测试方法6", validate = true)]
	public static bool Test6Validate()
	{
		//说明:检测并设置Test6是否可用,需配合Test6使用,单独不显示
		return _CheckedTest5_6 == 6;
	}

	// 设置选中状态, 即每次打开都会选中该项, 测试方法7和测试方法8交替选中
	private static int _CheckedTest7_8 = -1;
	[MenuItem("Tools/测试方法7")]
	public static void Test7()
	{
		_CheckedTest7_8 = 7;
		SetMenuSelected();
	}
	[MenuItem("Tools/测试方法8")]
	public static void Test8()
	{
		_CheckedTest7_8 = 8;
		SetMenuSelected();
	}

	private static void SetMenuSelected()
    {
		// Unity提供的API,可设置菜单的勾选状态
		Menu.SetChecked("Tools/测试方法7", _CheckedTest7_8 == 7);
		Menu.SetChecked("Tools/测试方法8", _CheckedTest7_8 == 8);
	}
}

打开文件

//[续]
public class UnityToolsEditor
{
	[MenuItem("Tools/OpenCS")]
	public static void OpenCS()
	{
		var paths = UnityEditor.AssetDatabase.FindAssets("文件名");
		if (paths.Length <= 0)
			return;
		var assetPath = AssetDatabase.GUIDToAssetPath(paths[0]);
		var obj = AssetImporter.GetAtPath(assetPath);
		AssetDatabase.OpenAsset(obj);
	}
}

增加类或者对象在Inspector窗口的功能(按钮,说明等)

//需要添加说明的类
public class UIBuilder
{

}
//Editor目录中
[CustomEditor(typeof("UIBuilder"))]
class UIBuilderCustomEditor: Editor
{
	public override void OnInspectorGUI()
    {
    	//实现具体的逻辑.
    	//可参考:https://blog.csdn.net/m0_37920739/article/details/104659247
    }
}

脚本编译完成后回调

//[续]
public class UnityToolsEditor
{
	//必须是静态方法
	[UnityEditor.Callbacks.DidReloadScripts]
	public static void ReloadScriptsCallback(){
	
	}
}

(修改后)资源重新加载后回调

public class WillSaveAssetsEditor : UnityEditor.AssetModificationProcessor
{
	//资源保存时会调用此函数,必须是静态函数
	public static void OnWillSaveAssets(string[] names)
	{

	}
}

编辑模式运行回调

//[续]
public class UnityToolsEditor
{
	//必须是静态方法
	[UnityEditor.InitializeOnEnterPlayMode]
	public static void OnEnterPlayModeCallBack(){
	
	}
}

ContextMenu及ContextMenuItem

public class TestObject : MonoBehaviour
{
	//修饰方法,属于类级别,选择该标签执行OnRandomData方法
	[ContextMenu("Random Data")]
	public void OnRandomData(){
		Debug.Log("OnTestMenu 被执行");
		OnRandomAge();
		OnRandomName();
	}
	
	//修饰属性,选择该标签执行OnRandomAge方法
	[ContextMenuItem("Random Age", "OnRandomAge")]
    public int Age;
    void OnRandomAge()
    {
        Age = new System.Random(DateTime.Now.Millisecond).Next(1, 100);
    }

	//修饰属性,选择该标签执行OnRandomAge方法
    [ContextMenuItem("Random Name", "OnRandomName")]
    public string Name;
    private void OnRandomName()
    {
        string[] names = new string[] { "Jack", "Jim", "Tomas", "Han", "Ann" };
        Name = names[new System.Random(DateTime.Now.Millisecond).Next(0, names.Lenth + 1)];
    }
}

Scane视图添加自定义菜单

//[续]
public class UnityToolsEditor
{
	//加载时调用的方法
	[InitializeOnLoadMethod]
	public static void InitializeOnLoad()
    {
		SceneView.duringSceneGui += (SceneView) =>
		{
			// 鼠标点击抬起,鼠标左右键都会响应到
			if(Event.current != null && 
				Event.current.type == EventType.MouseUp)
            {
				Debug.Log("鼠标点击事件");
            }
		};
    } 
}

ScriptableWizard

通过继承ScriptableWizard可以创建编辑器向导,Unity已经为我们封装好了一些变量、方法、消息。如:

  • 变量 errorString(设置向导的错误提示信息)、helpString(设置向导的帮助提示)、isValid(可以控制向导的Create Button和Other Button能否点击)。
  • 静态方法 DisplayWizard
  • 消息
    OnWizardCreate(当点击Create按钮的时候触发)
    OnWizardOtherButton(当点击Other按钮的时候)、
    OnWizardUpdate(当向导打开的瞬间或者向导中有输入参数的变化时触发)。
  • 示例:
//创建一个Cube提示
using UnityEditor;
using UnityEngine;

#region CreateHelper
public class CreateHelper : ScriptableWizard
{
    private static PrimitiveType _nType = PrimitiveType.Sphere;
    //声明为public可以被向导序列化显示在界面上,且可以改变其值
    public float size = 1f;
    public string name = "_N_U_L_L";
    //创建时的回调
    void OnWizardCreate()
    {
        GameObject obj = GameObject.CreatePrimitive(_nType);
        obj.transform.localScale = new Vector3(size, size, size);
        obj.name = name;
    }

    // 创建结束
    void OnWizardOtherButton()
    {
        //点击otherButton,需要调用Close()方法,才关闭向导。
        //但是点击createButton,并无需调用Close()方法而自动关闭。
        Close();
    }

    //输入过程提示
    void OnWizardUpdate()
    {
        if (name.Equals("_N_U_L_L"))
            name = _nType.ToString();
        switch (_nType)
        {
            case PrimitiveType.Sphere:
                OnSphereHelper();
                break;
            case PrimitiveType.Capsule:
                OnCapsuleHelper();
                break;
            case PrimitiveType.Cylinder:
                OnCylinderHelper();
                break;
            case PrimitiveType.Cube:
                OnCubeHelper();
                break;
            case PrimitiveType.Plane:
                OnPlaneHelper();
                break;
            case PrimitiveType.Quad:
                OnQuadHelper();
                break;
        }
    }


    #region Sphere
    [MenuItem("GameObject/3D Object/ASphere")]
    static void CreateSphere()
    {
        _nType = PrimitiveType.Sphere;
        ScriptableWizard.DisplayWizard<CreateHelper>("创建Sphere", "确定", "取消");
    }

    private void OnSphereHelper()
    {
        helpString = "创建Sphere,并修改默认名字防止重复";
        errorString = "";
        isValid = true;
        if (size >= 10)
        {
            errorString = "size要小于10";
            isValid = false;
        }
        else if (size <= 0)
        {
            errorString = "size要大于0";
            isValid = false;
        }
        if (string.IsNullOrEmpty(name))
        {
            errorString = "名字不能为空";
            isValid = false;
        }
        else if (name.Equals("Sphere"))
        {
            errorString = "修改默认名字";
            isValid = false;
        }
    }
    #endregion Sphere

    #region Capsule
    [MenuItem("GameObject/3D Object/ACapsule")]
    static void CreateCapsule()
    {
        _nType = PrimitiveType.Capsule;
        ScriptableWizard.DisplayWizard<CreateHelper>("创建Capsule", "确定", "取消");
    }

    private void OnCapsuleHelper()
    {
        helpString = "创建Capsule,并修改默认名字防止重复";
        errorString = "";
        isValid = true;
        if (size >= 10)
        {
            errorString = "size要小于10";
            isValid = false;
        }
        else if (size <= 0)
        {
            errorString = "size要大于0";
            isValid = false;
        }
        if (string.IsNullOrEmpty(name))
        {
            errorString = "名字不能为空";
            isValid = false;
        }
        else if (name.Equals("Capsule"))
        {
            errorString = "修改默认名字";
            isValid = false;
        }
    }
    #endregion Capsule

    #region Cylinder
    [MenuItem("GameObject/3D Object/ACylinder")]
    static void CreateCylinder()
    {
        _nType = PrimitiveType.Cylinder;
        ScriptableWizard.DisplayWizard<CreateHelper>("创建Cylinder", "确定", "取消");
    }

    private void OnCylinderHelper()
    {
        helpString = "创建Cylinder,并修改默认名字防止重复";
        errorString = "";
        isValid = true;
        if (size >= 10)
        {
            errorString = "size要小于10";
            isValid = false;
        }
        else if (size <= 0)
        {
            errorString = "size要大于0";
            isValid = false;
        }
        if (string.IsNullOrEmpty(name))
        {
            errorString = "名字不能为空";
            isValid = false;
        }
        else if (name.Equals("Cylinder"))
        {
            errorString = "修改默认名字";
            isValid = false;
        }
    }
    #endregion Cylinder

    #region Cube
    [MenuItem("GameObject/3D Object/ACube")]
    static void CreateCube()
    {
        _nType = PrimitiveType.Cube;
        ScriptableWizard.DisplayWizard<CreateHelper>("创建Cube", "确定", "取消");
    }

    private void OnCubeHelper()
    {
        helpString = "创建Cube,并修改默认名字防止重复";
        errorString = "";
        isValid = true;
        if (size >= 10)
        {
            errorString = "size要小于10";
            isValid = false;
        }
        else if (size <= 0)
        {
            errorString = "size要大于0";
            isValid = false;
        }
        if (string.IsNullOrEmpty(name))
        {
            errorString = "名字不能为空";
            isValid = false;
        }
        else if (name.Equals("Cube"))
        {
            errorString = "修改默认名字";
            isValid = false;
        }
    }
    #endregion Cube

    #region Plane
    [MenuItem("GameObject/3D Object/APlane")]
    static void CreatePlane()
    {
        _nType = PrimitiveType.Plane;
        ScriptableWizard.DisplayWizard<CreateHelper>("创建Plane", "确定", "取消");
    }

    private void OnPlaneHelper()
    {
        helpString = "创建Plane,并修改默认名字防止重复";
        errorString = "";
        isValid = true;
        if (size >= 10)
        {
            errorString = "size要小于10";
            isValid = false;
        }
        else if (size <= 0)
        {
            errorString = "size要大于0";
            isValid = false;
        }
        if (string.IsNullOrEmpty(name))
        {
            errorString = "名字不能为空";
            isValid = false;
        }
        else if (name.Equals("Plane"))
        {
            errorString = "修改默认名字";
            isValid = false;
        }
    }
    #endregion Plane

    #region Quad
    [MenuItem("GameObject/3D Object/AQuad")]
    static void CreateQuad()
    {
        _nType = PrimitiveType.Quad;
        ScriptableWizard.DisplayWizard<CreateHelper>("创建Quad", "确定", "取消");
    }

    private void OnQuadHelper()
    {
        helpString = "创建Quad,并修改默认名字防止重复";
        errorString = "";
        isValid = true;
        if (size >= 10)
        {
            errorString = "size要小于10";
            isValid = false;
        }
        else if (size <= 0)
        {
            errorString = "size要大于0";
            isValid = false;
        }
        if (string.IsNullOrEmpty(name))
        {
            errorString = "名字不能为空";
            isValid = false;
        }
        else if (name.Equals("Quad"))
        {
            errorString = "修改默认名字";
            isValid = false;
        }
    }
    #endregion Quad
}
#endregion CreateHelper

参考:

  1. unity 扩展编辑器 选中回调
  2. Unity使用随笔
  3. Unity编辑器扩展基本功能
  4. Unity检视面板重构(OnInspectorGUI重写)
  5. 【unity 编辑器拓展】
  6. Unity编辑器扩展
  7. Unity编辑器扩展小百科

你可能感兴趣的:(unity学习,unity,编辑器,游戏引擎)