赞
踩
[MenuItem(“Tools/mytest”)]
[MenuItem( “Tools/New Option %#a” )] 即Alt+Shift+A
[MenuItem( “Tools/Item2 _g” )] 即G
[MenuItem("CONTEXT/Rigidbody/Do Something")]
public static void DoSomething (MenuCommand command) {
Rigidbody body= command.context as Rigidbody ;
body.mass = 5 ;
}
[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;
}
添加组件到“添加组件”菜单下。
在继承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++; } }
继承该类可生成一个点击后关闭并重置的面板,可进行方便的对象创建修改操作
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 + "个对象"; } } }
每次Unity编译都会运行一次
方法 | 描述 |
---|---|
Label | 写入一个文本 |
BeginVertical | 开始垂直绘图 |
BeginHorizontal | 开始水平绘图 |
BeginScrollView | 开始滚动视图 |
Button | 按钮控件,放在IF语句中判断点击 |
方法 | 描述 |
---|---|
TextField | 文本框 |
EnumPopup | 枚举选项 |
IntField | 整数选项 |
ObjectField(object, typeof, false) | 一个Unity对象 |
PropertyField | 一个SerializedObject类中的对象 |
主面板
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; // 这其实是错误的写法,不应该直接操纵数据源,而是通过settings.FindProperty("datas")arraySize和settings.FindProperty("datas").GetArrayElementAtIndex(i) 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(); } // 修改asset文件 [MenuItem("Tools/CardDataArraysLoad")] public static void CardDataArraysLoad() { string path = "Assets/Configs/CardDataArrayConfig.asset"; CardDataArrayConfig config = AssetDatabase.LoadAssetAtPath<CardDataArrayConfig>(path); config.baseCardDatas = new CardData[baseCardDatas.Count]; EditorUtility.SetDirty(config); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } }
数据类
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; }
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; }
数据类
using System;
using UnityEngine;
[Serializable]
public class MyCustomVariable
{
public string name;
public int key;
public float value;
public bool flag;
public KeyCode input;
public Color color;
public GameObject obj;
public Vector3 dir;
}
使用PropertyDrawer实例化到一行中
using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; //给MyCustomVariable指定编译器实例化渲染方式 [CustomPropertyDrawer(typeof(MyCustomVariable))] public class MyCustomVariableDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { //重载BeginProperty EditorGUI.BeginProperty(position,label,property); //绘制单元格头的标签名,不需要可以去掉 position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); //Unity默认的每个属性字段都会占用一行,我们这里希望一条自定义Property占一行 //要是实现这个要求我们分三步: 1. 取消缩进 2. 设置PropertyField 3.还原缩进 //不要缩进子字段,由我们自定义间距 var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; //计算要用到的属性显示rect Rect(x,y,width,height)x,y是左顶点 var nameRect = new Rect(position.x, position.y, 50, position.height); var keyRect = new Rect(position.x + 60, position.y, 40, position.height); var flagRect = new Rect(position.x + 110, position.y, 20, position.height); var inputRect = new Rect(position.x + 140, position.y, 60, position.height); var colorRect = new Rect(position.x + 210, position.y, 50, position.height); var dirRect = new Rect(position.x + 270, position.y, 100, position.height); var objRect = new Rect(position.x + 380, position.y, position.width - 390, position.height); //绘制字段 - 将GUIContent.none传递给每个字段,以便绘制它们而不是用标签 //属性绘制器不支持布局来创建GUI; //因此,您必须使用的类是EditorGUI而不是EditorGUILayout。这就是为什么要给每个属性指定Rect EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("name"), GUIContent.none); EditorGUI.PropertyField(keyRect, property.FindPropertyRelative("key"), GUIContent.none); EditorGUI.PropertyField(flagRect, property.FindPropertyRelative("flag"), GUIContent.none); EditorGUI.PropertyField(inputRect, property.FindPropertyRelative("input"), GUIContent.none); EditorGUI.PropertyField(colorRect, property.FindPropertyRelative("color"), GUIContent.none); EditorGUI.PropertyField(dirRect, property.FindPropertyRelative("dir"), GUIContent.none); EditorGUI.PropertyField(objRect, property.FindPropertyRelative("obj"), GUIContent.none); //将缩进还原 EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); } //设定单元格高度,默认返回为默认高度 public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return base.GetPropertyHeight(property, label); } }
using System; using Cinemachine.Editor; using Framework.GameObjectBinder.Views.Variables; using UnityEditor; using UnityEditor.Rendering; using UnityEditorInternal; using UnityEngine; [CustomPropertyDrawer(typeof(MyCustomVaribleArray))] public class MyCustomVariableArrayDrawer : PropertyDrawer { private ReorderableList list; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { //获取要渲染的列表 property = property.FindPropertyRelative("variables"); //设定动作函数 if (list == null) { list = new ReorderableList(property.serializedObject, property, true, true, true, true) { multiSelect = true, elementHeight = 22, drawElementCallback = DrawElement, drawHeaderCallback = DrawHeader, // onAddCallback = onAddDropdownCallback = OnAddElement, onRemoveCallback = OnRemoveElement, drawElementBackgroundCallback = DrawElementBackground }; } else { list.serializedProperty = property; } list.DoList(position); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { // 基础高度 var height = base.GetPropertyHeight(property, label) + 60; // 计算列表 var variables = property.FindPropertyRelative("variables"); for (var i = 0; i < variables.arraySize; i++) height += EditorGUI.GetPropertyHeight(variables.GetArrayElementAtIndex(i)) + 5; return height; } private void DrawElement(Rect rect, int index, bool isActive, bool isFocused) { var variables = list.serializedProperty; if (index < 0 || index >= variables.arraySize) return; var variable = variables.GetArrayElementAtIndex(index); var x = rect.x; var y = rect.y + 2; var width = rect.width - 20; var height = rect.height - 4; var variableRect = new Rect(x, y, width, height); EditorGUI.PropertyField(variableRect, variable, GUIContent.none); var buttonRect = new Rect(variableRect.xMax + 5, y + 1, 18, 18); if (GUI.Button(buttonRect, new GUIContent("+"))) { Debug.Log("点击了按钮"); } } private void DrawHeader(Rect rect) { GUI.Label(rect, "数据列表"); } private void OnAddElement(Rect rect, ReorderableList list) { var variables = list.serializedProperty; //当前列表数量 var index = variables.arraySize > 0 ? variables.arraySize : 0; //生成多选菜单 var menu = new GenericMenu(); //根据枚举项,决定生成菜单选项名称 foreach (KeyCode variableType in Enum.GetValues(typeof(KeyCode))) { var type = variableType; menu.AddItem(new GUIContent(variableType.ToString()), false, context => { AddVariable(variables, index, type); }, null); } menu.ShowAsContext(); } //根据选项,生成元素 protected virtual void AddVariable(SerializedProperty variables, int index, KeyCode type) { if (index < 0 || index > variables.arraySize) return; variables.serializedObject.Update(); //在在列表底插入元素,相当于追加元素 variables.InsertArrayElementAtIndex(index); //获取到最新添加的元素,并根据选项修改枚举值 var variableProperty = variables.GetArrayElementAtIndex(index); variableProperty.FindPropertyRelative("input").SetEnumValue(type); //写入数据到实例化对象 variables.serializedObject.ApplyModifiedProperties(); //清除焦点 GUI.FocusControl(null); } private void OnRemoveElement(ReorderableList list) { var variables = list.serializedProperty; var selectedIndices = list.selectedIndices; //如果没选择任何表单元素,那么删除最后一个 if (selectedIndices.Count == 0) { AskRemoveVariable(variables, variables.arraySize - 1); } //删除所有选中的对象 for (var i = selectedIndices.Count - 1; i >= 0; i--) { var index = selectedIndices[i]; list.Deselect(index); AskRemoveVariable(variables, index); } } protected virtual void AskRemoveVariable(SerializedProperty variables, int index) { if (variables == null || index < 0 || index >= variables.arraySize) return; var variable = variables.GetArrayElementAtIndex(index); var name = variable.FindPropertyRelative("name").stringValue; // 某项被填入值时,弹出提示避免直接清除 if (string.IsNullOrEmpty(name)) { RemoveVariable(variables, index); return; } if (EditorUtility.DisplayDialog("Confirm delete", string.Format("Are you sure you want to delete the item named \"{0}\"?", name), "Yes", "Cancel")) RemoveVariable(variables, index); } protected virtual void RemoveVariable(SerializedProperty variables, int index) { if (index < 0 || index >= variables.arraySize) return; variables.serializedObject.Update(); //清除表单元素 variables.DeleteArrayElementAtIndex(index); //写入数据到实例化对象 variables.serializedObject.ApplyModifiedProperties(); GUI.FocusControl(null); } private void DrawElementBackground(Rect rect, int index, bool isActive, bool isFocused) { ReorderableList.defaultBehaviours.DrawElementBackground(rect, index, isActive, false, true); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。