当前位置:网站首页>Unity-编辑器扩展(Editor)
Unity-编辑器扩展(Editor)
2022-08-02 14:11:00 【莉萝爱萝莉】
1. 基本介绍
1. MenuItem
- 使用 MenuItem 特性,让静态函数作为一个菜单栏功能
[MenuItem(“Tools/mytest”)]
- 第三个参数层级,可控制显示的顺序。不同级别的参数最小值和最大值之间最小为11
- 添加快捷键
- %-CTRL
- # -Shift
- & -Alt
[MenuItem( “Tools/New Option %#a” )] 即Alt+Shift+A
[MenuItem( “Tools/Item2 _g” )] 即G
- 特殊路径
- Assets/[] -添加到“Assets”菜单下,同时也显示在右键单击项目视图时弹出的菜单中。
- Asset/Create/[] - 添加在“Assets ->Create”子菜单中。
- CONTEXT/[任意组件名]/[] - 菜单项将出现在给定组件的右键单击菜单中。
[MenuItem("CONTEXT/Rigidbody/Do Something")]
public static void DoSomething (MenuCommand command) {
Rigidbody body= command.context as Rigidbody ;
body.mass = 5 ;
}
- GameObject/[] 菜单项会出现在层级的右键菜单中。但你需要给定一个层级 < 50
[MenuItem(“GameObject/mytest2”, false, 12)]
- 限定
通过第二个参数来限定该按钮是否启用
// 效果
[MenuItem("Assets/SetMass", false, 12)]
static void SetMass()
{
Rigidbody rigidbody = Selection.gameObjects[0].GetComponent<Rigidbody>();
rigidbody.mass = 5;
}
// 约束
[MenuItem("Assets/SetMass", true)]
static bool SetMassOption()
{
return Selection.gameObjects[0].GetComponent<Rigidbody>() != null;
}
2. AddComponentMenu
添加组件到“添加组件”菜单下。
3. ContextMenu、ContextMenuItem
在继承MonoBehaviour时:
特性 | 描述 |
---|---|
ContextMenu | 添加到自身的右键菜单中 |
ContextMenuItem | 添加到菜单列表 |
public class MyObject : MonoBehaviour
{
[ContextMenuItem("+1", "AddValue")]
public int value;
public string data;
[ContextMenu("重置")]
void ResetData()
{
value = 0;
data = "";
}
void AddValue()
{
value++;
}
}
4. ScriptableWizard
继承该类可生成一个点击后关闭并重置的面板,可进行方便的对象创建修改操作
using UnityEngine;
using UnityEditor;
public class MyObjectEditor : ScriptableWizard
{
// 参数
public string changeName = "未命名";
// 创建按钮到编辑器,并设置按钮名称以及标题
[MenuItem("Tools/CreateWizard")]
public static void CreateWizard()
{
// 一个点击后关闭并重置的面板
DisplayWizard<MyObjectEditor>("统一修改", "修改", "第二个按钮");
}
// 点击后关闭界面并执行
private void OnWizardCreate()
{
// 修改选取对象的名字
foreach (var obj in Selection.gameObjects)
{
// 操作记录到unity记录中,以便ctrl+z撤回
Undo.RecordObject(obj, "修改名字");
obj.name = changeName;
}
// 在界面显示提示信息,仅在未关闭时显示
ShowNotification(new GUIContent(Selection.gameObjects.Length + "个对象被修改了"));
}
// 点击另一个按钮,这不会关闭界面
private void OnWizardOtherButton() => OnWizardCreate();
// 仅在初始化和值改变时变化
private void OnWizardUpdate() => HelpInfor();
// 选中物体时调用
private void OnSelectionChange() => HelpInfor();
// 用于提示信息
void HelpInfor()
{
if (Selection.gameObjects.Length == 0)
{
// 错误信息
errorString = "请选择一个对象!";
helpString = "";
}
else
{
// 帮助信息
errorString = "";
helpString = "您选择了" + Selection.gameObjects.Length + "个对象";
}
}
}
5. [UnityEditor.InitializeOnLoadMethod]
每次Unity编译都会运行一次
2. 编译器绘图
1. 绘图方法
- GUILayout
方法 | 描述 |
---|---|
Label | 写入一个文本 |
BeginVertical | 开始垂直绘图 |
BeginHorizontal | 开始水平绘图 |
BeginScrollView | 开始滚动视图 |
Button | 按钮控件,放在IF语句中判断点击 |
- EditorGUILayout
方法 | 描述 |
---|---|
TextField | 文本框 |
EnumPopup | 枚举选项 |
IntField | 整数选项 |
ObjectField(object, typeof, false) | 一个Unity对象 |
PropertyField | 一个SerializedObject类中的对象 |
2. 示例:窗口形式
主面板
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class AudioWindowEditor : EditorWindow
{
static SaveData data;
string path = "Assets/Resources/MainData.asset";
string text;
string search = "";
static GUIStyle textStyle;
static AudioWindowEditor window;
[MenuItem("Tools/test")]
public static void CreateWindow()
{
// 固定大小窗口
// Rect rect = new Rect(0, 0, 800, 600);
// AudioWindowEditor window = GetWindowWithRect(typeof(AudioWindowEditor), rect) as AudioWindowEditor;
if (window == null)
{
window = GetWindow<AudioWindowEditor>("数据管理");
textStyle = new GUIStyle("HeaderLabel");
textStyle.fontSize = 24;
}
window.Show();
}
/// <summary>
/// 每秒调用十次
/// </summary>
private void OnInspectorUpdate()
{
}
private void OnGUI()
{
// 设置标题和其显示的值,将其值返回
// text = EditorGUILayout.TextField("输入文字", text);
if (data == null) data = AssetDatabase.LoadAssetAtPath<SaveData>(path);
if (data == null)
{
// new SaveData()可替换为 CreateInstance<SaveData>()
AssetDatabase.CreateAsset(new SaveData(), path);
AssetDatabase.SaveAssets();
data = AssetDatabase.LoadAssetAtPath<SaveData>(path);
}
var settings = new SerializedObject(data);
GUI.skin.label.fontSize = 16;
GUILayout.Label("基本内容");
EditorGUILayout.PropertyField(settings.FindProperty("key"), new GUIContent("名称"));
// 第一栏
// GUILayout.BeginHorizontal("Wizard Box");
search = EditorGUILayout.TextField("", search, "SearchTextField");
// GUILayout.EndHorizontal();
// 第二栏
GUILayout.BeginVertical("Wizard Box", GUILayout.MaxHeight(1));
GUILayout.BeginHorizontal(new GUIStyle("HelpBox")
{
padding = new RectOffset(10, 0, 4, 4)
});
GUILayout.Label("名称", new GUIStyle("SettingsHeader")
{
fontSize = 16,
alignment = TextAnchor.MiddleLeft,
});
GUILayout.Label("值", new GUIStyle("SettingsHeader")
{
fontSize = 16,
alignment = TextAnchor.MiddleLeft,
});
GUILayout.EndHorizontal();
KeyValue removeOne = null;
KeyValue moveUp = null;
KeyValue moveDown = null;
for (int i = 0; i < data.keyvalues.Count; i++)
{
var dataSlot = data.keyvalues[i];
if (dataSlot.key == null) dataSlot.key = "";
if (dataSlot.key.ToLower().Contains(search.ToLower()))
{
GUILayout.Space(2);
GUILayout.BeginHorizontal("HelpBox");
dataSlot.key = EditorGUILayout.TextField(dataSlot.key);
dataSlot.value = (GameObject)EditorGUILayout.ObjectField(dataSlot.value, typeof(GameObject), false);
if (i != 0)
{
if (GUILayout.Button("↑", GUILayout.MaxWidth(24), GUILayout.MaxHeight(18))) moveUp = dataSlot;
}
else GUILayout.Button("", GUILayout.MaxWidth(24), GUILayout.MaxHeight(18));
if (i != data.keyvalues.Count - 1)
{
if (GUILayout.Button("↓", GUILayout.MaxWidth(24), GUILayout.MaxHeight(18))) moveDown = dataSlot;
}
else GUILayout.Button("", GUILayout.MaxWidth(24), GUILayout.MaxHeight(18));
if (GUILayout.Button("-", GUILayout.MaxWidth(24), GUILayout.MaxHeight(18))) removeOne = dataSlot;
GUILayout.EndHorizontal();
}
}
if (removeOne != null) data.keyvalues.Remove(removeOne);
if (moveUp != null)
{
int index = -1;
for (int i = 0; i < data.keyvalues.Count; i++) if (data.keyvalues[i] == moveUp) index = i;
if (index != -1)
{
var move = moveUp;
data.keyvalues.Remove(moveUp);
data.keyvalues.Insert(index - 1, move);
}
}
if (moveDown != null)
{
int index = -1;
for (int i = 0; i < data.keyvalues.Count; i++) if (data.keyvalues[i] == moveDown) index = i;
if (index != -1)
{
var move = moveDown;
data.keyvalues.Remove(moveDown);
data.keyvalues.Insert(index + 1, move);
}
}
if (GUILayout.Button("+"))
{
data.keyvalues.Add(new KeyValue());
}
GUILayout.EndVertical();
// 应用修改
settings.ApplyModifiedPropertiesWithoutUndo();
}
}
数据类
using UnityEngine;
using System.Collections.Generic;
public class SaveData : ScriptableObject
{
public string key;
public List<KeyValue> keyvalues;
}
[System.Serializable]
public class KeyValue
{
public string key;
public GameObject value;
}
3. 示例:项目设置中添加项形式
using UnityEditor;
using UnityEngine;
public class MainDataEditor
{
static MainData data;
[SettingsProvider]
public static SettingsProvider MyCustom()
{
string path = "Assets/Resources/Data/MainData.asset";
var provider = new SettingsProvider("MainData", SettingsScope.Project)
{
// 默认情况下,如果未提供标签,则路径的最后一个标记将用作显示名称。
label = "主线资源库",
// 填充搜索关键字
// 创建SettingsProvider并将其绘图(IMGUI)功能初始化
guiHandler = (searchContext) =>
{
if (data == null) data = AssetDatabase.LoadAssetAtPath<MainData>(path);
if (data == null)
{
// new MainData()可替换为 CreateInstance<MainData>()
AssetDatabase.CreateAsset(new MainData(), path);
AssetDatabase.SaveAssets();
data = AssetDatabase.LoadAssetAtPath<MainData>(path);
}
var settings = new SerializedObject(data);
GUI.skin.label.fontSize = 16;
GUILayout.Label("基本扩展");
EditorGUILayout.PropertyField(settings.FindProperty("blood"), new GUIContent("溅血特效"));
EditorGUILayout.PropertyField(settings.FindProperty("spark"), new GUIContent("火星特效"));
EditorGUILayout.PropertyField(settings.FindProperty("sharp"), new GUIContent("锋利特效"));
// 应用修改
settings.ApplyModifiedPropertiesWithoutUndo();
}
};
return provider;
}
}
数据类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
[CreateAssetMenu(fileName = "MainData", menuName = "Data/MainData", order = 1)]
public class MainData : ScriptableObject
{
/// <summary>
/// 溅血特效
/// </summary>
public GameObject blood;
/// <summary>
/// 火星特效
/// </summary>
public GameObject spark;
/// <summary>
/// 锋利特效
/// </summary>
public GameObject sharp;
/// <summary>
/// 结束的线
/// </summary>
public GameObject endLine;
/// <summary>
/// 结束光环
/// </summary>
public GameObject endNova;
/// <summary>
/// 孔明灯
/// </summary>
public GameObject KongMingLight;
/// <summary>
/// 枪线
/// </summary>
public GameObject weaponLine;
public TileBase[] tileBases;
public AudioClip[] audioClips;
/// <summary>
/// 背包
/// </summary>
public Bag bag;
/// <summary>
/// 提示信息
/// </summary>
public Infor infor;
public Dialog dialog;
/// <summary>
/// 失败面板
/// </summary>
public Fail failPanel;
public Fail winPanel;
public LoadScene loadScenePanel;
public Sprite[] move_Sprs;
public WeaponData[] weapons;
/// <summary>
/// 保存值
/// </summary>
public SaveData saveData;
public Player player;
/// <summary>
/// 物品列表
/// </summary>
public Good[] goods;
}
边栏推荐
- Mysql之MVCC
- MATLAB绘图函数ezplot入门详解
- What should I do if I install a solid-state drive in Win10 and still have obvious lags?
- pytorch模型转libtorch和onnx格式的通用代码
- 一篇文章彻底理解Redis的持久化:RDB、AOF
- 第二十八章:解题技巧
- Compilation error D8021: Invalid numeric argument '/Wextra' cl command line error d8021 invalid numeric argument '/Wextra'
- 为vscode配置clangd
- Open the door to electricity "Circuit" (3): Talk about different resistance and conductance
- IPV4和IPV6是什么?
猜你喜欢
Codeforces Round #605 (Div. 3)
C语言函数参数传递模式入门详解
What should I do if Windows 10 cannot connect to the printer?Solutions for not using the printer
推开机电的大门《电路》(一):电压,电流,参考方向
Installation and configuration of Spark and related ecological components - quick recall
第二十五章:一文掌握while循环
将SSE指令转换为ARM NEON指令
Introduction to C language function parameter passing mode
远程连接Ubuntu中的Mysql
队列与栈
随机推荐
mysql的索引结构为什么选用B+树?
第二十五章:一文掌握while循环
MATLAB绘图函数ezplot入门详解
将SSE指令转换为ARM NEON指令
MATLAB绘图命令fimplicit绘制隐函数图形入门详解
pytorch模型转libtorch和onnx格式的通用代码
Codeforces Round #624 (Div. 3)
永久更改pip源
如何用硬币模拟1/3的概率,以及任意概率?
Spark及相关生态组件安装配置——快速回忆
Codeforces Round #605 (Div. 3)
使用libcurl将Opencv Mat的图像上传到文件服务器,基于post请求和ftp协议两种方法
奇技淫巧-位运算
利用plot_surface命令绘制复杂曲面入门详解
【系统设计与实现】基于flink的分心驾驶预测与数据分析系统
Win7 encounters an error and cannot boot into the desktop normally, how to solve it?
Win10 Settings screen out from lack of sleep?Win10 set the method that never sleep
推开机电的大门《电路》(一):电压,电流,参考方向
第二十八章:解题技巧
Detailed introduction to the hierarchical method of binary tree creation