编辑器扩展只是在编辑项目中运行,发布出来是不会运行的。

固定创建一个文件夹Editor:所有的资源或者代码都不会被打包进去。

01、使用MenuItem添加菜单栏按钮

脚本不需要作为组件存在,可以不用继承MonoBehaviour

如何删除引用(每个函数调用的次数):工具-文本编辑器

如果需要显示行号:

工具-选项-文本编辑器-C#-行号

引用命名空间:using UnityEditor;

[MenuItem("Tools/test/test1")]:在菜单栏会有Tools这一栏,点击显示test,点击test显示test1

 public class Tools  {
[MenuItem("Tools/test/test1")]
static void Test()//要是静态方法,不然会出现警告
{
Debug.Log("Test");//UnityEngine里面的
}
}

[MenuItem("Tools/test/test2")]:test下会有两个子按钮test1、test2(但是不能完全一样,方法名也不能重复)

   [MenuItem("Tools/test/test1")]
static void Test()
{
Debug.Log("Test");//UnityEngine
}
[MenuItem("Tools/test/test2")]
static void Test2()
{
Debug.Log("Test");
}

也可以在现有的菜单路径下添加:

     [MenuItem("Window/mytool/test1")]
static void Test3()
{
Debug.Log("Test");
}

每个菜单栏里面都有一根横线进行分类:

[MenuItem("GameObject/my tool")]//会添加到最下面即第四类

为自己添加的菜单栏进行分组(即设置第三个参数,优先级越小越显示在上面,相邻的两个菜单栏(下面是test3 与show info相邻)的优先级相差11(或者大于11)就会多一个分割线):

unity里面认为优先级相差小就在同一组里面

  //每一个菜单栏的priority优先级默认为1000,第三个参数
[MenuItem("Tools/show info",false,)]
static void Test1()
{
//Debug.Log(Selection.activeGameObject.name );//是我们第一个选择的游戏物体
//Debug.Log(Selection.objects.Length); }
//%=ctrl #=shift &=alt
[MenuItem("Tools/test2 %q",false,)]
static void Test2()
{
Debug.Log("Test2");
}
[MenuItem("Tools/test3 %t",false,)]
static void Test3()
{
Debug.Log("Test3");
}

要放在现有菜单栏中间某一组中,要知道每个一组有多少个,一般都猜想。

如果要放在hierarchy或者project等面板右键的的弹出框菜单栏里面,也是需要自己根据位置去猜想,第一级菜单看应该放在哪个,比如project对应的菜单是assets。

02、给组件的右键菜单栏添加按钮

注意强转的两种方式不同:

as强转时如果后面的类型和要强转的类型不一样的时候不会报错,但是会但会一个空值给前者,使用其就会报空指针的错误

而直接加类型强转就会报错

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor; public class PlayerEditor {
[MenuItem("CONTEXT/PlayerHealth/InitHealthAndSpeed")]// CONTEXT 组件名 按钮名 系统自动调用下面的函数,编辑器大部分不需要运行时执行
static void InitHealthAndSpeed( MenuCommand cmd )//menucommand是当前正在操作的组件(context,userData两个参数)
{
//Debug.Log(cmd.context.GetType().FullName);//得到context完整类型名
//Debug.Log(cmd.context.name);//输出的是组件所在游戏物体的名字
CompleteProject.PlayerHealth health = cmd.context as CompleteProject.PlayerHealth;//强制转化得到当前操作的对象,注意不能在前面加类型强制转型
health.startingHealth = ;
health.flashSpeed = ;
Debug.Log("Init");
}
//添加清除刚体的的阻力和重力 1e-07约等于1
[MenuItem("CONTEXT/Rigidbody/Clear")]//CONTEXT 是固定的
static void ClearMassAndGravity( MenuCommand cmd )
{
Rigidbody rgd = cmd.context as Rigidbody;
rgd.mass = ;
rgd.useGravity = false;
}
}

03、学习使用selection获取选择的游戏物体(成员为静态,直接用类名访问,如果没有选中物体则为空,active开头的是选择场景中的游戏物体(在inspector面板上显示的))

点击自己添加的按钮实现将选中的所有游戏物体执行该按钮对应的功能函数。

objects参数:获得当前选择的游戏物体数组,可以获得所有选中的游戏物体(包括project)

activeObject参数:在inspector面板上显示的游戏物体,多选的就会显示第一个(包括预制体)

activetransform:通过得到的activeobject物体上的transform组件,只能获取一个

删除功能实现:

    [MenuItem("GameObject/my delete", false, )]
static void Mydelete()
{
foreach (Object o in Selection.objects)//不选择返回的是空数组
{
//GameObject.DestroyImmediate(o);//编辑器模式下不能用destory,能用GameObject.DestroyImmediate,删除之后无法用ctrl+Z无法撤销
Undo.DestroyObjectImmediate(o);//利用Undo进行的删除操作 是可以撤销的
}
//想要有撤销功能首先需要把删除操作注册到 操作记录里面
}

给菜单项添加快捷键:

  [MenuItem("Tools/test3 _t",false,)]//表示test3的快捷键为T,一定要有空格和快捷键
static void Test3()
{
Debug.Log("Test3");
}
设置组合快捷键:
    //%代表ctrl #代表shift &代表alt
[MenuItem("Tools/test2 %q",false,)]
static void Test2()
{
Debug.Log("Test2");
}

04、控制菜单项是否启用的功能(第二个参数,比如实现没有选择游戏物体的时候设置上面的mydelete删除键为不能按(不启用)的状态)

true表示按钮对应的这个调用函数是验证函数。点击game object会先执行上面的验证方法,不能按为灰色(不可点击状态)

问题:右键弹出菜单与game object菜单下的按钮点击状态显示不一样?

 [MenuItem("GameObject/my delete", true, )]//路径保持一致,第二个参数为true表示是给下面的响应函数作为验证的,必须要有一个返回值,根据返回值判断是否能判断
static bool MyDeleteValidate()
{
if (Selection.objects.Length > )
return true;//选择了游戏物体返回true,判定下面的方法能够执行
else
return false;
} [MenuItem("GameObject/my delete", false, )]
static void Mydelete()
{
foreach (Object o in Selection.objects)
{
//GameObject.DestroyImmediate(o);
Undo.DestroyObjectImmediate(o);//利用Undo进行的删除操作 是可以撤销的
}
//需要把删除操作注册到 操作记录里面
}

05、contextmenu和contextmenuitem的使用(给组件添加右键,可以直接在组件中使用,不需要引用editor命名空间,在unityEngine命名空间下)

对于系统内置组件无法修改脚本代码,只能通过context方式添加右键功能,对于自己写的脚本组件即可用以下方法

要给那个组件添加右键,就在该组件里面添加方法

 [ContextMenu("setColor")]
void setColor()
{
flashColour = setColor.green;
}

API中特性一般是attribute结尾,使用的时候不需要attribute

contextmenuitem给脚本的属性添加功能。

右键添加给脚本组件的变量血量属性添加增加方法(点击startingHealth右键才有按钮出现):

[ContextMenuItem("按钮的名字","执行的方法(必须要存在)")]
[ContextMenuItem("AddHp","addHp")
public int startingHealth = ; void addHp()
{
   startingHealth +=20;
}

07、创建对话框(有批量修改游戏物体的需求,比如后期游戏对敌人prefabs修改血量什么的属性且更改的值是不确定的,可以用方法06,可是一个个点也很麻烦,如果能全选之后弹出对话框批量修改属性)

可以在弹出的对话框输入值。创建对话框的类后要创建一个对话框,对话框默认有一个close的按钮

对话框类:

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor; public class EnemyChange : ScriptableWizard {//对话框类要继承ScriptableWizard 类,定义的字段都会显示在对话框中
//实现统一修改敌人
[MenuItem("Tools/CreateWizard")]//创建对话框按钮,menuItem可以在任何脚本都可以放,最好将其与对应的修改属性放在一个脚本里
static void CreateWizard()
{
ScriptableWizard.DisplayWizard<EnemyChange>("统一修改敌人","Change And Close","Change");//第二个参数是对话框左下角按钮的名字,第三个参数是otherButtonName按钮
}
//继承了对话框类脚本中的属性是会显示在对话框上的(公有的)
public int changeStartHealthValue = ;
public int changeSinkSpeedValue = ; const string changeStartHealthValueKey = "EnemyChange.changeStartHealthValue";
const string changeSinkSpeedValueKey = "EnemyChange.changeSinkSpeedValue";
//当窗口被创建出来的时候调用的
void OnEnable()
{
//第二个参数是传默认值,因为第一次没有保存值
changeStartHealthValue = EditorPrefs.GetInt(changeStartHealthValueKey, changeStartHealthValue);
changeSinkSpeedValue = EditorPrefs.GetInt(changeSinkSpeedValueKey, changeSinkSpeedValue);
}
//检测create按钮的点击,对话框上面的create(不一定是create,左下角的按钮)按钮(点击会自动调用此函数并关闭对话框)
void OnWizardCreate()
{
GameObject[] enemyPrefabs = Selection.gameObjects;//取得所有选择的方法,gameobjects包括预制体
EditorUtility.DisplayProgressBar("进度", "0/" + enemyPrefabs.Length + " 完成修改值", );
int count = ;
foreach (GameObject go in enemyPrefabs)//遍历所有选择的object
{
CompleteProject.EnemyHealth hp = go.GetComponent<CompleteProject.EnemyHealth>();//得到选中物体上的要修改属性所属的属性,注意加上正确的命名空间
Undo.RecordObject(hp, "change health and speed");//记录做了哪些更改的函数(第二个参数是记录撤销这个步骤的名字,可以随意更改),撤销实现,要注意要放在更改对应属性之前,不然没有用
//修改成我们设置的值
hp.startingHealth += changeStartHealthValue;
hp.sinkSpeed += changeSinkSpeedValue;//即不能把记录操作函数(undo)放在这之后
count++;
//进度条
EditorUtility.DisplayProgressBar("进度", count+"/" + enemyPrefabs.Length + " 完成修改值", (float)count/enemyPrefabs.Length);
}
//代码清除进度条
EditorUtility.ClearProgressBar();
//显示提示信息,对话框被关闭也会关闭
ShowNotification(new GUIContent(Selection.gameObjects.Length + "个游戏物体的值被修改了"));
}
//otherButtonName按钮响应函数
void OnWizardOtherButton()
{
OnWizardCreate();
}
//当前字段值修改的时候会被调用
void OnWizardUpdate()
{
//设置为空的原因:保证每次两个提示信息都要实时更新(因为原先没有选择敌人的时候会出现错误提示而没有帮助提示,选择一个之后会显示帮助提示而错误提示没有更新)
errorString = null;
helpString = null;
if (Selection.gameObjects.Length > )
{
helpString = "您当前选择了" + Selection.gameObjects.Length + "个敌人";//设置帮助提示,如果想要实时显示当前选择的敌人人数
}
else
{
errorString = "请选择至少一个敌人";
}
//本地保存对话框修改的值
EditorPrefs.SetInt(changeStartHealthValueKey, changeStartHealthValue);
EditorPrefs.SetInt(changeSinkSpeedValueKey, changeSinkSpeedValue);
} //当选择的物体发生改变调用的函数
void OnSelectionChange()
{
OnWizardUpdate();
}
}

对话框中一些有用的方法属性:

三个事件方法(untiy会自动帮我们调用):

void OnWizardCreate() :检测create按钮的点击,对话框上面的create(不一定是create,左下角的按钮)按钮(点击会自动调用此函数并关闭对话框)
void OnWizardUpdate() :面板被创建(对话框弹出来的时候)会被调用一次,当前字段值修改的时候会被调用(一修改就调用)
void OnWizardOtherButton() :otherButtonName按钮响应函数

示提示信息字段:
errorString :显示错误信息

helpString:显示提示信息
对话框默认只有一个按钮,如果想要设置多个按钮:
ScriptableWizard DisplayWizard (title : string, klass : System.Type, createButtonName : string = "Create", otherButtonName : string = "") :创建一个按钮

显示进度条:

DisplayCancelableProgressBar:能够点击取消的进度条

DisplayProgressBar:只能由代码清除的进度条

   

 08.创建自定义窗口

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
//要继承editorWindow
public class MyWindow : EditorWindow { [MenuItem("Window/show mywindow")]
static void ShowMyWindow()
{
MyWindow window= EditorWindow.GetWindow<MyWindow>();
window.Show();
}
//如果想要在窗口中添加东西,使用onGUI绘制
private string name="";
void OnGUI()
{
GUILayout.Label("这是我的窗口");
name = GUILayout.TextField(name);
if (GUILayout.Button("创建"))
{
GameObject go = new GameObject(name);//创建游戏物体
Undo.RegisterCreatedObjectUndo(go, "create gameobject");//添加到unity操作记录,方便撤销
}
} }

平常使用的(持续添加):

1.RangeAttribute

在int或者float类型上使用,限制输入值的范围

public class TestRange : MonoBehaviour
{
[Range(, )]
public int HP;
}

2.[SerializeField,Tooltip("前景动画视频名字需加后缀")]:序列化并在Inspector面板上添加注释(鼠标放上去会显示Tooltip文字)

3.HeaderAttribute:在一些字段前面加上注释,显示在inspector面板上该属性的上面

 using UnityEngine;
using System.Collections; public class ExampleClass : MonoBehaviour {
[Header("Health Settings")]
public int health = ;
public int maxHealth = ;
[Header("Shield Settings")]
public int shield = ;
public int maxShield = ;
}

4.[HideInInspector] :在ispector面板上隐藏

5.RequireComponent:当你添加一个脚本,使用requirecomponent到一个游戏对象,所需的组件将自动被添加到游戏对象。

using UnityEngine;

// PlayerScript requires the GameObject to have a Rigidbody component
[RequireComponent(typeof(Rigidbody))]
public class PlayerScript : MonoBehaviour
{
Rigidbody rb; void Start()
{
rb = GetComponent<Rigidbody>();
} void FixedUpdate()
{
rb.AddForce(Vector3.up);
}
}

6.TextAreaAttribute:属性使一个字符串被编辑以高度灵活和可滚动文本区域。

using UnityEngine;

public class TextAreaExample : MonoBehaviour
{
[TextArea]
public string MyTextArea;
}

7.RPC:同步

unity3D编辑器扩展的更多相关文章

  1. Unity3D编辑器扩展(六)——模态窗口

    前面我们已经写了5篇关于编辑器的,这是第六篇,也是最后一篇: Unity3D编辑器扩展(一)——定义自己的菜单按钮 Unity3D编辑器扩展(二)——定义自己的窗口 Unity3D编辑器扩展(三)—— ...

  2. Unity3D编辑器扩展(五)——常用特性(Attribute)以及Selection类

    前面写了四篇关于编辑器的: Unity3D编辑器扩展(一)——定义自己的菜单按钮 Unity3D编辑器扩展(二)——定义自己的窗口 Unity3D编辑器扩展(三)——使用GUI绘制窗口 Unity3D ...

  3. Unity3D编辑器扩展(四)——扩展自己的组件

    前面已经写了三篇: Unity3D编辑器扩展(一)——定义自己的菜单按钮 Unity3D编辑器扩展(二)——定义自己的窗口 Unity3D编辑器扩展(三)——使用GUI绘制窗口 今天写第四篇,扩展自己 ...

  4. Unity3d编辑器扩展学习笔记

    编辑器扩展 1.添加菜单栏:把特性应用于静态方法 参数1:菜单名的空格后面是定义快捷键(单符号得用"_"开头,组合键%=Ctrl,#=Shift,&=Alt) 参数2:通过 ...

  5. Unity3D编辑器扩展(一)——定义自己的菜单按钮

    Unity3D 引擎的编辑器拥有很强的扩展性,用的好可以帮我们省很多事情.在这里记录下如何去扩展 Unity3D 的编辑器,定制属于我们自己的开发环境. 本篇主要讲解在 Unity3D 引擎的各个窗口 ...

  6. Unity3D编辑器扩展(三)——使用GUI绘制窗口

    前两篇分别讲解了创建菜单https://www.cnblogs.com/xiaoyulong/p/10115053.html和创建窗口https://www.cnblogs.com/xiaoyulon ...

  7. Unity3D编辑器扩展(二)——定义自己的窗口

    上一篇我们讲了如何定义菜单按钮 https://www.cnblogs.com/xiaoyulong/p/10115053.html 这一篇我们讲如何定义自己的窗口. 定义窗口我们需要继承 Edito ...

  8. [Unity3D]编辑器扩展之数组或List显示

    效果如下: 源码如下: using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace XM.Edi ...

  9. Unity 3D编辑器扩展介绍、教程(二) —— 创建窗口

    Unity编辑器扩展教程(二) 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 一 Brief Introd ...

随机推荐

  1. ntp服务及其配置

    集群中使用NTP服务 简介 之前搭建zookeeper时报了一个错,我以为是ntp的问题,结果不是.这里详细学习一下如何在集群中使用ntp服务. 什么是ntp服务 来自ntp的百度百科: NTP服务器 ...

  2. 刨根问底 HTTP 和 WebSocket 协议(下)

    上篇介绍了HTTP1.1协议的基本内容,这篇文章将继续分析WebSocket协议,然后对这两个进行简单的比较. WebSocket WebSocket协议还很年轻,RFC文档相比HTTP的发布时间也很 ...

  3. py.test

    只运行某一个用例 pytest test_mod.py::test_func 或者 pytest test_mod.py::TestClass::test_method

  4. httpClient实现

    1.实现功能 向关注了微信公众号的微信用户群发消息.(可以是所有的用户,也可以是提供了微信openid的微信用户集合) 2.基本步骤 前提: 已经有认证的公众号或者测试公众账号 发送消息步骤: 发送一 ...

  5. Windows下搭建React Native Android开发环境

    准备工作 安装JDK 安装Android SDK 安装C++环境 安装node.js 安装react-native命令行工具 创建项目 运行packager 运行模拟器 安卓运行 安卓调试 安装JDK ...

  6. LCD驱动程序(一)

    LCD显示原理: 在JZ2440上,想要让LCD显示,需要几个部分1.LCD硬件 2.开发板上的LCD控制器 3.SDRAM内存存放数据FramBuffer 4.可能还需要一个调色板(实际上是一块内存 ...

  7. Struts2+hibernate+spring 配置事物

    今天自信看了看hibernate的事物配置问题,转载了其他人的日志,仅用来学习. struts+hibernate+spring事务配置 (2009-01-14 21:49:47) 转载▼ 标签: i ...

  8. Asp.Net MVC3中如何进行单元测试?

    下面我们就以一个示例演示一下如何进行单元测试? public Model.UserInfo UpdateEntity(Model.UserInfo entity) { db.UserInfo.Atta ...

  9. python基础-第五篇-5.1冒泡排序

    几个月过去了,小白逐渐对公司的后端服务熟悉了,不过这天小白又接到一封神秘邮件,是景女神发来的:公司急需一批对语言算法有些了解的优秀员工,鉴于你在公司的表现很不错,现在给到你一个培训机会,请速到开发部报 ...

  10. 北京君正集成电路的Newton平台--穿戴式

    版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/hellomxj1/article/details/25324125   Newton1开发平台 • 很适合 ...