目录
近来无事,巩固一下unity编辑器扩展相关知识,一顿胡乱折腾,将四处网罗的东西东拼西凑写一写,打发时间
编辑器常见修饰符
- [SerializeField] 序列化,将私有属性暴露在属性面板,可编辑
- [HideInInspector] 隐藏属性,修饰属性,隐藏暴露在属性面板的属性
- [NonSerialized] 不可序列化,修饰属性,且在Inspector面板上隐藏
- [Header(“描述”)] 标题栏,修饰属性,在属性面板显示
- [Tooltip(“描述”)] 提示字段,修饰属性,鼠标指向的时候显示
- [Space(5)] 间隔距离,修饰属性
- [Range(min,max)] 限制范围,修饰值类型数据
- [InitializeOnLoadMethod] 加载时调用, 修饰方法,方法必须是static方法
- [InitializeOnLoad] 加载时调用, 修饰类,
- [AddComponentMenu(“路径”)] 修饰类,可以在指定的路径的直接添加该类
- [ContextMenuItem(“标签名”,“方法名”)] 修饰属性,将属性设置为该标签时,执行方法,类需继承自MonoBehaviour
- [ContextItem(“标签名”)] 修饰方法,在挂载脚本(类级别)设置该标签时,执行方法,类需继承自MonoBehaviour
- [MenuItem(“目录路径”) 特殊的路径,修饰方法:
- GameObject/ 菜单出现在GameObject节点下
- Assets/ 菜单出现在Assets节点下(Project面板下右键弹出的面板内容和Assets节点展开的是一致的)
- 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
参考:
本文含有隐藏内容,请 开通VIP 后查看