鄙人接触Unity也算有一段时间了,不过在开发的过程中,可能会有各种各样的需求是Unity本身无法完成的,不过Unity3D引擎非常强大的地方之一就是其可拓展性,也就是说Unity允许开发者去自定义菜单等等完成开发者想要的各种的需求,鄙人于网上各种找资料并动手操作实践了一番,在这边小小的总结一下:
首先是最为简单的操作,在Unity编辑器的上方工具栏里面添加自己的一些按键,需要在Assets/Editor文件夹里新建个脚本,鄙人这边为了方便理解就命名为:ToolsMenu.cs。由于是对Unity编辑器进行拓展,那么就需要引用using UnityEditor;另外脚本也不需要继承自MonoBehaviour了,还有把脚本自带的Update()与Start()方法删掉。具体操作代码如下:
using UnityEngine;
using UnityEditor;
public class ToolsMenu {
[MenuItem("Tools/Button1",false,1)]//菜单栏路径,是否为验证方法,菜单优先级
static void Button1()
{
Debug.Log("皮皮虾我们走!");
}
}
保存完毕后,在回到Unity编辑器界面,发现上方工具栏处变化
点击之后执行Button1方法控制台输出。其实也可以给自己的按键添加快捷键:
using UnityEngine;
using UnityEditor;
public class ToolsMenu {
[MenuItem("Tools/Button1 _Y",false,1)]
static void Button1()
{
Debug.Log("皮皮虾我们走!");
}
}
如代码所示,键盘Y键就为方法的快捷键,其实把“_Y”换成“%Y”就是ctrl+Y,类似的有“&”对应alt,“#”对应shift等;
这边解释下静态方法前中括号的内容,括号内的字符串指定了按键在菜单栏的指定位置,bool值表示该方法是否为验证方法,最后的int型数表示
该选项的优先级,菜单内的选项根据有限级由小到大排列。顺带一提,要是相邻选项的优先级相差值大于等于11的话菜单栏内会出现分隔线:
using UnityEngine;
using UnityEditor;
public class ToolsMenu {
[MenuItem("Tools/Button1 _Y",false,1)]
static void Button1()
{
Debug.Log("皮皮虾我们走!");
}
[MenuItem("Tools/Button2 %U",false,12)]
static void Button2()
{
Debug.Log("大闸蟹我们走!");
}
}
结果如图:
其次再说明一下那个诡异的bool值控制的验证方法,上代码:
using UnityEngine;
using UnityEditor;
public class ToolsMenu {
[MenuItem("Tools/Button1", false, 1)]
static void Button1()
{
foreach (Object g in Selection.objects)//删除全部选中游戏物体
{
GameObject.DestroyImmediate(g);
}
}
[MenuItem("Tools/Button1", true, 1)]
static bool Button1Validate()
{
if (Selection.objects.Length > 0)
return true;
else
return false;
}
}
在这里设置验证方法中括号内除了bool值之外都跟Button1的一样,效果是先执行Button1Validate()方法后根据判断返回的值决定相应菜单选项是否可选。
保存脚本后,如果选中场景中的至少一样GameObject后如图:
Button1按键为可选状态,如果不选择任何GameObject:
则Button1为灰色不可选状态。
顺带一提这边直接使用DestroyImmediate()方法删除物体后是无法Ctrl+Z撤销的,不过换成Undo.DestroyObjectImmediate(g);即可。
方法1:在Editor内部脚本上动手,上代码:
using UnityEngine;
using UnityEditor;
public class ToolsMenu {
[MenuItem("CONTEXT/MyScript/LogGameObjectName")]
static void LogName(MenuCommand cmd)//MenuCommand为当前正在操作的组件
{
Debug.Log(cmd.context.name);//输出当前组件所在GameObject名
}
}
结果如图:
即在中括号格式["CONTEXT/组件名/添加的选项名"],便可完成添加选项。
方法2:这回是在脚本本身动手脚,上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyScript : MonoBehaviour {
void Start () {
}
void Update () {
}
[ContextMenu("LogGameObjectName2")]
void LogName()
{
Debug.Log(gameObject.name);
}
}
运行结果如图:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyScript : MonoBehaviour {
[ContextMenuItem("Add Life", "AddLife")]//给该字段添加了个右键菜单,[ContextMenuItem("按键名","方法名")]
public float life = 0;
void Start () {
}
void Update () {
}
void AddLife()
{
life += 100;
}
}
运行效果如图:
在MyScript组件的Life属性处右键可以出现菜单栏选项Add Life ,点击后执行脚本中的AddLife()方法。
举个简单的例子,实现改变选中Game Object的名称的功能:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ChangeName : ScriptableWizard//继承自可编程对话框
{
[MenuItem("Tools/ChangeNameWizard", false, 50)]
static void CreateWizard()
{
//创建对话框,标题为“统一修改名称”,把默认按钮Create命名为"Change And Close",增加按键"Change"
ScriptableWizard.DisplayWizard("统一修改名称", "Change And Close", "Change");
}
private void OnWizardCreate()//按下默认按键"Change And Close",同时有关闭对话框的效果
{
Debug.Log("按下默认按键");
}
private void OnWizardOtherButton()//按下增加的按键"Change"
{
Debug.Log("按下增加的按键");
}
}
运行结果如图:
点击Tools/ChangeNameWizard按键后,出现对话框,点击下发的Change和ChangeAndClose按键分别执行OnWizardOtherButton()与
接下来上完整代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ChangeName : ScriptableWizard//继承自可编程对话框
{
public string changeName = "GameObject";//物体命名
[MenuItem("Tools/ChangeNameWizard", false, 50)]
static void CreateWizard()
{
ScriptableWizard.DisplayWizard("统一修改名称", "Change And Close", "Change");//创建对话框,标题为“统一修改名称”,
//把默认按钮Create命名为"Change And Close",增加按键"Change"
}
private void OnWizardCreate()//按下默认按键"Change And Close",同时有关闭对话框的效果
{
Debug.Log("按下默认按键");
foreach(GameObject g in Selection.objects)
{
g.name = changeName;
}
ShowNotification(new GUIContent("有" + Selection.gameObjects.Length + "个游戏物体被更名为" + changeName));//字幕输出
}
private void OnWizardOtherButton()//按下增加的按键"Change"
{
Debug.Log("按下增加的按键");
foreach (GameObject g in Selection.objects)
{
g.name = changeName;
}
ShowNotification(new GUIContent("有" + Selection.gameObjects.Length + "个游戏物体被更名为"+changeName));//字幕输出
}
private void OnWizardUpdate()//当字段值发生改变时一直调用
{
Debug.Log("Update");
errorString = null;
helpString = null;
if (Selection.gameObjects.Length > 0)
{
helpString = "您当前选择了" + Selection.gameObjects.Length + "个物体";
}
else
{
errorString = "请至少选择一个物体";
}
}
}
测试截图:在点击Change之前,选中4个GameObject
我们可以看见4个Game Object被更名为“皮皮虾”......
代码中比较可能有疑问的地方打上了必要的备注在此就不必多言....
关于窗口界面布局的编程在OnGUI()方法中实现,这边举个简单的例子:创建空物体
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class MyWindow : EditorWindow {
[MenuItem("Tools/ShowMyWindow",false,80)]
static void ShowMyWindow()
{
//Debug.Log("Show My Window");
MyWindow window = EditorWindow.GetWindow();//创建Window
window.Show();
}
private string name = "Object";
private void OnGUI()
{
GUILayout.Label("我的窗口");
name = GUILayout.TextField(name);//显示输入框
if (GUILayout.Button("创建"))//显示按钮
{
GameObject g = new GameObject(name);
ShowNotification(new GUIContent("您创建了"+name));//字幕输出
Undo.RegisterCreatedObjectUndo(g,"Create Gameobject");//记录从而可以撤销
}
}
}
运行效果如图:
点击ShowMyWindow按键之后出现窗口,点击窗口上的Create按钮:
鄙人的小结到此就先告一段落,要是有什么小瑕疵啥的还望阁下海涵海涵,最后头像镇楼。