Unity流水账11:编辑器工具总结(一)

2023-12-07 05:58

本文主要是介绍Unity流水账11:编辑器工具总结(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、MenuItem:创建菜单项

  (1) 描述
  MenuItem属性可以让你在主菜单和inspector context菜单中添加菜单项。
  MenuItem属性可以将任何static函数转换为菜单命令。只有static函数可以使用MenuItem属性。
  创建热键,可以使用以下特殊字符:%(在Windows上表示ctrl,在macOS表示cmd),#(shift)和&(alt)。如果不需要特殊的修饰键组合,则可以在下划线后给出该组合键。例如,菜单绑定快捷键shift-alt-g,可使用"MyMenu/Do Something #&g"。若要创建带有热键g且没有按键修饰符的菜单项,可使用 “MyMenu/Do Something _g”。
  也支持一些特殊的键盘键作为热键,例如“ #LEFT”被映射为左移。支持特殊键如下:LEFT,RIGHT,UP,DOWN,F1 … F12,HOME,END,PGUP,PGDN。
  热键文本之前必须带有空格字符(例如"MyMenu/Do_g"中g不会被解释为热键,而"MyMenu/Do _g"会被解释为热键)。
  将菜单项添加到“ GameObject /”菜单中以创建自定义游戏对象时,确保调用GameObjectUtility.SetParentAndAlign以确保在上下文单击的情况下正确地重新创建了新的GameObject(可参见下面的示例)。函数还应该调用 Undo.RegisterCreatedObjectUndo以创建可撤消的命令,并调用Selection.activeObject 以使新创建的对象被选中。注意,为了将“ GameObject /”中的菜单项传播到hierarchy的Create下拉菜单和hierarchy context菜单中,必须将其与其他GameObject创建菜单项分组。可以通过将其优先级设置为10来实现(请参见下面的示例)。注意,出于传统目的,“ GameObject / Create Other”中未设置显式优先级的MenuItems将获得优先级10,而不是默认的1000-我们鼓励使用比“ Create Other”更具描述性的类别名称,并将显式优先级设置为10 。

  创建菜单项


public class EditorTest
{//在测试菜单中添加测试菜单项[MenuItem("测试/测试")]static void DoSomething(){Debug.Log("测试...");}
}

工具截图
  创建带启用条件的菜单项

using UnityEditor;
using UnityEngine;public class EditorTest
{//需条件才能点击的菜单项[MenuItem("测试/测试")]static void DoSomething(){Debug.Log("测试...");}//上面菜单的条件[MenuItem("测试/测试", true)]static bool ValidateDoSomething(){return Selection.activeTransform != null;}
}

工具截图
  创建带快捷键的菜单项

using UnityEditor;
using UnityEngine;public class EditorTest
{//添加带有快捷键的菜单(在windows为ctrl-g,在macOS为cmd-g)[MenuItem("测试/测试 %g")]static void DoSomething(){Debug.Log("测试...");}
}
//按住ctrl+g输出测试...

  创建组件CONTENT菜单

public class EditorTest
{//添加CONTEXT菜单[MenuItem("CONTEXT/Transform/测试")]static void DoSomething(MenuCommand conmand){Transform body = (Transform)conmand.context;body.position = new Vector3(10, 10, 10);Debug.Log("设置Transform position为 " + body.position);}
}

工具截图
  创建GameObje菜单

//File、Editor、Assets、Component、Window、Help菜单同理,只需吧GameObject改成对应的即可。
using UnityEditor;
using UnityEngine;public class EditorTest
{//添加GameObject菜单项,并设置菜单项位置,但如何控制GameObject/测试的位置?//[MenuItem("GameObject/测试", false, 0)]//[MenuItem("GameObject/测试", false, 1)][MenuItem("GameObject/测试/测试0", false, 0)]static void CreateCustomGameObject0(MenuCommand conmand){GameObject go = new GameObject("Custom Game Object1");//设置新建物体未选中物体的子节点GameObjectUtility.SetParentAndAlign(go, conmand.context as GameObject);Undo.RegisterCreatedObjectUndo(go, "Create" + go.name);Selection.activeObject = go;}[MenuItem("GameObject/测试/测试1", false, 11)]static void CreateCustomGameObject1(MenuCommand conmand){GameObject go = new GameObject("Custom Game Object1");//设置新建物体未选中物体的子节点GameObjectUtility.SetParentAndAlign(go, conmand.context as GameObject);Undo.RegisterCreatedObjectUndo(go, "Create" + go.name);Selection.activeObject = go;}//与上一个菜单间隔11个单位有分割线[MenuItem("GameObject/测试/测试2", false, 22)]static void CreateCustomGameObject2(MenuCommand conmand){GameObject go = new GameObject("Custom Game Object2");//设置新建物体未选中物体的子节点GameObjectUtility.SetParentAndAlign(go, conmand.context as GameObject);Undo.RegisterCreatedObjectUndo(go, "Create" + go.name);Selection.activeObject = go;}
}

工具截图
工具截图
工具截图
  (2) Constructors

MenuItem:创建一个菜单项,并在菜单项选中的时候调用其对应的static函数。MenuItem是脚本函数之前的属性。这使该函数出现在Unity菜单系统中。菜单位置由itemName 参数指定。isValidateFunction用于使MenuItem函数成为具有相同itemName参数的脚本函数之前执行的函数。第二个参数是布尔值。如果将此参数设置为该参数true,它将把关联的函数标记为在执行第二个脚本函数之前调用的函数。第二个具有相同功能的脚本功能itemName将在接下来执行。priority确定如何在菜单系统中排序对应的脚本函数。将该整数值与其他脚本函数上的值进行比较。如果该整数值大于其他值,则MenuItem脚本函数将位于列表的底部。priority还可以用于将脚本功能列表分为几组进行管理。
函数定义:
1.public MenuItem(string itemName);
2.public MenuItem(stirng itemName, bool isValidateFunction);
3.public MenuItem(string itemName, bool isValidateFunciton, int priority);
函数参数:
1.itemName:该itemName是类似菜单项路径的名称。例如,菜单项可以是“ GameObject/Do Something”。
2.isValidateFunction:如果isValidateFunction为true,则这是一个菜单项的验证函数,在调用相同itemName的菜单项函数时会先调用此验证函数。
3.priority:菜单项的显示顺序。
代码示例1using UnityEditor;
using UnityEngine;public class EditorTest
{//添加菜单项1[MenuItem("测试/测试1",false, 100)]static void Example1(){Debug.Log("测试1...");}//添加菜单项2[MenuItem("测试/测试2", false, 100)]static void Example2(){Debug.Log("测试2...");}
}
代码示例2:下面这个示例显示了测试菜单如何用分割线分割菜单项。当priority参数间隔超过10个时,就会发生这种情况。注意大于10才能在菜单中创建分割线。但是按照下面的例子,脚本函数之间的优先级差值需要大于等于11.若将下面的111改为110则没有分割线。
using UnityEditor;
using UnityEngine;public class EditorTest
{//添加菜单项1[MenuItem("测试/测试1",false, 100)]static void Example1(){Debug.Log("测试1...");}//添加菜单项2[MenuItem("测试/测试2", false, 111)]static void Example2(){Debug.Log("测试2...");}
}

示例1结果
二、ScriptableObject:创建保存数据的asset
  (1) 描述
  如果要创建不需要附加到游戏对象上的对象,可以派生一个类。
  这对于仅用于存储数据的资产很有用。
  要创建绑定到项目中资产的ScriptableObject实例,可使用CreateAssetMenuAttribute属性。
  此类不支持null-conditional operator (?.) 和 null-coalescing operator (??) 。

  (2) Static Methods

CreateInstance:创建scriptable对象的实例。若要通过Editor用户界面创建绑定到.asset文件的ScriptableObject实例,可使用CreateAssetMenuAttribute。
函数定义:
1.public static ScriptableObject CreateInstance(string className);
2.public static ScriptableObject CreateInstance(Type type);
3.public static T CreateInstance();
函数参数:
1.className:要创建的ScriptableObject的type对应的名称。
2.type:要创建的ScriptableObject的类型,System.Type实例。
函数返回值:
ScriptableObject:创建的ScriptableObject
T:创建的ScriptableObject

  (3) Message

Awake:启动ScriptableObject脚本时将调用此函数。ScriptableObject脚本启动时将调用Awake。 这是在游戏启动时发生的,类似于MonoBehavior.Awake。
函数定义:ScriptableObject.Awake()
代码示例:第一个是ScriptableObject脚本。 这实现了与MonoBehaviour分开的代码。 第二个是与MonoBehaviour相关的小型脚本,该脚本从ScriptableObject脚本访问值。using UnityEngine;//添加菜单项到Assets/Create
[CreateAssetMenuAttribute]
//[CreateAssetMenu]
//一个ScriptableObject示例脚本。
// A和B成员变量实现与MonoBehaviour无关的功能。
public class ScriptObjExample : ScriptableObject
{int a = 10;int[] b = new int[5] { 0, 17, 34, 42, 67 };public int A{get { return a; }}//返回b数组中的值;如果x超出范围,则返回-1public int B(int x){if (x >= 0 && x <= 5)return b[x];elsereturn -1;}//创建Asset以及CreateInstance的时候会调用Awake->OnEnablepublic void Awake(){Debug.Log("ScriptObjExample Awake");}public void OnEnable(){Debug.Log("ScriptObjExample OnEnable");}//调用CreateInstance后,游戏停止运行会调用OnDisable->OnDestroypublic void OnDisable(){Debug.Log("ScriptObjExample OnDisable");}public void OnDestroy(){Debug.Log("ScriptObjExample OnDestroy");}
}//创建和访问ScriptableObjectTest
public class ScriptableObjectTest : MonoBehaviour
{ScriptObjExample test;private void Start(){Debug.Log("ScriptableObjectTest Start");test = (ScriptObjExample)ScriptableObject.CreateInstance(typeof(ScriptObjExample));print(test.A);print(test.B(3));print(test.B(-3));}
}
OnDestroy:当scriptable的对象将被销毁时,将调用此函数。OnDestroy不能是协程co-routine。
函数定义:ScriptableObject.OnDestroy()
代码示例:同上
OnDisable:当scriptable的对象超出范围时,将调用此函数。当对象被销毁时也调用该方法,该方法可用于任何清除代码。 编译完成后重新加载脚本时,将调用OnDisable,并在加载脚本后调用OnEnable。OnDisable不能是协程co-routine。
函数定义:ScriptableObject.OnDisable()
代码示例:同上
OnEnable:加载对象时调用此函数。OnEnable不能是协程co-routine。
函数定义:ScriptableObject.OnEnable()
代码示例:同上

  (4) CreateAssetMenuAttribute
    (1) 描述
    将ScriptableObject派生的类型在"Assets / Create"子菜单中列出,点击子菜单时可以创建该类型的实例并将其存储为“ .asset”文件。
    (2) Properties

fileName:此类型新创建实例使用的默认文件名。注意,任何自定义文件名都必须以“ .asset”结尾,这样才能被Unity正确处理。
函数定义:public string fileName;
menuName:"Assets/Create"菜单中该类型显示的名称。与其他菜单项代码一样,使用正斜杠(“ /”)路径分隔符将项分组为子菜单。 例如,将MenuName指定为“ Gameplay / Objective”将导致该类型的菜单项在“ Create”的子菜单“ Gameplay”的子菜单“ Objective”中。
函数定义:public string menuName;
order:菜单项在“Assets/Create”菜单中的位置。
函数定义:public int order;

三、SettingsProvider:创建Setting/Preferences菜单项

  (1) 描述
  SettingsProvider是配置类,用于指定应如何在“Setting”或“Preferences”窗口中显示Project setting或prefeerence。
  为了添加新的Project setting或preference页面,可定义一个SettingsProvider。 SettingsProvider类提供了钩子来显示任何UI(使用IMGUI或UIElements绘制它)。 它还提供了一个API,该API允许您以两种方式指定在“Setting”和“Preferences”窗口中使用的关键字:
  1)搜索栏过滤掉没有匹配关键字的SettingsProviders。
  2)属性标签以匹配的关键字突出显示。

  代码示例

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;//创建新类型Setting Asset
class MyCustomSettings : ScriptableObject
{public const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";[SerializeField] private int m_Number;[SerializeField] private string m_SomeString;internal static MyCustomSettings GetOrCreateSetting(){var settings = AssetDatabase.LoadAssetAtPath<MyCustomSettings>(k_MyCustomSettingsPath);if (settings == null){settings = ScriptableObject.CreateInstance<MyCustomSettings>();settings.m_Number = 42;settings.m_SomeString = "The answer to the universe";AssetDatabase.CreateAsset(settings, k_MyCustomSettingsPath);AssetDatabase.SaveAssets();}return settings;}internal static SerializedObject GetSerializedSettings(){return new SerializedObject(GetOrCreateSetting());}
}//使用IMGUI为绘图框架注册SettingsProvider:
static class MyCustomSettingsIMGUIRegister
{[SettingsProvider]public static SettingsProvider CreateMyCustomSettingsProvider(){//第一个参数是Setting窗口中的路径//第二个参数是此设置的范围:它仅出现在Project Setting窗口中。var provider = new SettingsProvider("Project/MyCustomIMGUISettings", SettingsScope.Project){//默认情况下,如果未提供label,则路径的最后一个字段用作显示名称。label = "Custom IMGUI",//创建SettingsProvider并用它初始化其绘制(IMGUI)函数:guiHandler = (searchContext) =>{var settings = MyCustomSettings.GetSerializedSettings();EditorGUILayout.PropertyField(settings.FindProperty("m_Number"), new GUIContent("My Number"));EditorGUILayout.PropertyField(settings.FindProperty("m_SomeString"), new GUIContent("My String"));},//填充搜索关键字以启用智能过滤搜索并突出显示标签:keywords = new HashSet<string>(new[] { "Number", "Some String" })};return provider;}
}

示例结果

using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;
using System.Collections.Generic;//创建新类型Setting Asset
class MyCustomSettings : ScriptableObject
{public const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";[SerializeField] private int m_Number;[SerializeField] private string m_SomeString;internal static MyCustomSettings GetOrCreateSetting(){var settings = AssetDatabase.LoadAssetAtPath<MyCustomSettings>(k_MyCustomSettingsPath);if (settings == null){settings = ScriptableObject.CreateInstance<MyCustomSettings>();settings.m_Number = 42;settings.m_SomeString = "The answer to the universe";AssetDatabase.CreateAsset(settings, k_MyCustomSettingsPath);AssetDatabase.SaveAssets();}return settings;}internal static SerializedObject GetSerializedSettings(){return new SerializedObject(GetOrCreateSetting());}
}
//使用UIElements为绘图框架注册SettingsProvider:
static class MyCustomSettingsUIElementsRegister
{[SettingsProvider]public static SettingsProvider CreateMyCustomSettingsProvider(){//第一个参数是Setting窗口中的路径//第二个参数是此设置的范围:它仅出现在Project Setting窗口中。var provider = new SettingsProvider("Project/MyCustomUIElementSettings", SettingsScope.Project){label = "Custom UI Elements",//当用户单击Setting窗口中的Setting菜单项时,将调用activateHandler。activateHandler = (searchContext, rootElement) =>{var settings = MyCustomSettings.GetSerializedSettings();//rootElement是一个VisualElement。 如果向其添加任何子项,则不会调用OnGUI函数,//因为SettingsProvider使用UIElements绘图框架。var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/settings_ui.uss");rootElement.styleSheets.Add(styleSheet);var title = new Label(){text = "Custom UI Elements"};title.AddToClassList("title");rootElement.Add(title);var properties = new VisualElement(){style ={flexDirection = FlexDirection.Column}};properties.AddToClassList("property-list");rootElement.Add(properties);var tf = new TextField(){value = settings.FindProperty("m_SomeString").stringValue};tf.AddToClassList("property-value");properties.Add(tf);},keywords = new HashSet<string>(new[] { "Number", "Some String" })};return provider;}
}

结果示例

using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;
using System.IO;//创建新类型Setting Asset
class MyCustomSettings : ScriptableObject
{public const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";[SerializeField] private int m_Number;[SerializeField] private string m_SomeString;internal static MyCustomSettings GetOrCreateSetting(){var settings = AssetDatabase.LoadAssetAtPath<MyCustomSettings>(k_MyCustomSettingsPath);if (settings == null){settings = ScriptableObject.CreateInstance<MyCustomSettings>();settings.m_Number = 42;settings.m_SomeString = "The answer to the universe";AssetDatabase.CreateAsset(settings, k_MyCustomSettingsPath);AssetDatabase.SaveAssets();}return settings;}internal static SerializedObject GetSerializedSettings(){return new SerializedObject(GetOrCreateSetting());}
}
//通过从SettingsProvider派生类来创建MyCustomSettingsProvider
class MyCustomSettingsProvider : SettingsProvider
{private SerializedObject m_CustomSettings;class Styles{public static GUIContent number = new GUIContent("My Number");public static GUIContent someString = new GUIContent("Some string");}const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";public MyCustomSettingsProvider(string path, SettingsScope scope = SettingsScope.User) : base(path, scope) { }public static bool IsSettingsAvailable(){return File.Exists(k_MyCustomSettingsPath);}public override void OnActivate(string searchContext, VisualElement rootElement){//当用户单击Setting窗口中的MyCustom菜单项时,将调用此函数。m_CustomSettings = MyCustomSettings.GetSerializedSettings();}public override void OnGUI(string searchContext){//使用IMGUI显示UIEditorGUILayout.PropertyField(m_CustomSettings.FindProperty("m_Number"), Styles.number);EditorGUILayout.PropertyField(m_CustomSettings.FindProperty("m_SomeString"), Styles.someString);}//注册SettingsProvider[SettingsProvider]public static SettingsProvider CreateMyCustomSettingsProvider(){if (IsSettingsAvailable()){var provider = new MyCustomSettingsProvider("Project/MyCustomSettignsProvider", SettingsScope.Project);//自动从样式中提取所有关键字provider.keywords = GetSearchKeywordsFromGUIContentProperties<Styles>();return provider;}//Settings Asset不存在; 无需在Settings窗口中显示任何内容。return null;}
}

示例结果
  (2) Properties

activateHandler:重写SettingsProvider.OnActivate。
函数定义:public Action<string,VisualElement> activateHandler;
deactivateHandler:重写SettingsProvider.OnDeactivate。
函数定义:public Action deactivateHandler;
footerBarGuiHandler:重写SettingsProvider.OnFooterBarGUI。
函数定义:public Action footerBarGuiHandler;
guiHandler:重写SettingsProvider.OnGUI。
函数定义:public Action<string> guiHandler;
hasSearchInterestHandler:重写SettingsProvider.HasSearchInterest。
函数定义:public Func<string,bool> hasSearchInterestHandler;
inspectorUpdateHandler:重写SettingsProvider.OnInspectorUpdate。
函数定义:public Action inspectorUpdateHandler;
keywords:获取或设置关键字列表,以与用户搜索的内容进行比较。 当用户在Settings窗口的搜索框中输入值时,SettingsProvider.HasSearchInterest尝试将那些关键字与此列表匹配。
函数定义:public IEnumerable<string> keywords;
label:获取或设置SettingsProvider在Settings窗口中显示的显示名称。 如果未设置,则Settings窗口将使用SettingsProvider.settingsPath的最后一个标记。
函数定义:public string label;
代码示例:
using UnityEditor;class SettingsProviderExamples
{[SettingsProvider]static SettingsProvider CreateVariousSettingsProviders1(){//新的Project设置菜单显示在其自己的根部分(MyOwnSection)中,但未分组在所有核心设置下。var p = new SettingsProvider("MyOwnSection/MySettings", SettingsScope.Project);//here p.label = "MySettings"return p;}[SettingsProvider]static SettingsProvider CreateVariousSettingsProviders2(){//第一个参数是用于将Settings放置在树形视图中的唯一ID。//如果指定了label,则它将成为SettingsProvider的显示名称。var p2 = new SettingsProvider("MyOwnSection/MySettingsOfDoom", SettingsScope.Project){label = "A more proper Settings Name"};return p2;}[SettingsProvider]static SettingsProvider CreateVariousSettingsProviders3(){//第二个参数是SettingsProvider的范围。 它确定此SettingsProvider是否出现在//Settings窗口(用于通过SettingsScope.Project指定的项目设置)//或是否出现在Preferences窗口中(通过SettingsScope.User指定时)var p3 = new SettingsProvider("Preferences/Multi touch", SettingsScope.User);return p3;}
}

结果示例

scope:获取SettingsProvider的范围。 确定SettingsProvider是出现在Preferences窗口(SettingsScope.User)还是Settings窗口(SettingsScope.Project)中。
函数定义:public SettingsScope scope;
settingsPath:获取用于将SettingsProvider放置在Settings窗口的树视图中的路径。 该路径在所有其他设置路径中应该是唯一的,并且应使用“ /”作为其分隔符。
函数定义:public string settingsPath;
titleBarGuiHandler:重写SettingsProvider.OnTitleBarGUI。
函数定义:public Action titleBarGuiHandler;

  (3) Constructors

SettingsProvider:创建一个新的SettingsProvider。
函数定义:public SettingsProvider(string path, SettingsScope scopes, IEnumerable<string> keywords);
函数参数:
1.path:Settings窗口中设置的路径。 使用“ /”作为分隔符。 如果没有提供label,则最后一个字符串将设置为label。
2.scope:设置范围。 确定设置显示的位置:在Settings或Preferences窗口中。
3.keywords:与用户搜索内容进行比较的关键字列表。 当用户在Settings窗口的搜索框中输入值时,SettingsProvider.HasSearchInterest尝试将那些关键字与此列表匹配。

  (4) Public Methods

HasSearchInterest:检查当用户在Settings窗口搜索框中键入内容时,是否应显示SettingsProvider。 SettingsProvider尝试将搜索词(甚至部分匹配)与任何SettingsProvider.keywords匹配。 搜索不区分大小写。
函数定义:public bool HasSearchInterest(string searchContext);
函数参数:
1.searchContext:用户在Settings窗口的搜索框搜索词。
函数返回值:
1.bool:如果SettingsProvider匹配搜索词并且应该显示,则为True。
OnActivate:使用此功能可为用户单击Settings窗口中的菜单项提供一个处理程序。 你可以用此函数获取菜单项asset或设置UIElements UI。
函数定义:public void OnActivate(string searchContext, UIElements.VisualElement rootElement);
函数参数:
1.searchContext:在“设置”窗口上的搜索框中搜索上下文。
2.rootElement:UIElements树的根节点。 如果添加到此根目录,则SettingsProvider使用UIElements而不是调用SettingsProvider.OnGUI来构建UI。 如果不添加到此VisualElement,则必须使用IMGUI来构建UI。
代码示例1using UnityEditor;
using UnityEngine.UIElements;
using UnityEngine;
class MyCustomSettings : ScriptableObject
{public const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";[SerializeField] private int m_Number;[SerializeField] private string m_SomeString;internal static MyCustomSettings GetOrCreateSetting(){var settings = AssetDatabase.LoadAssetAtPath<MyCustomSettings>(k_MyCustomSettingsPath);if (settings == null){settings = ScriptableObject.CreateInstance<MyCustomSettings>();settings.m_Number = 42;settings.m_SomeString = "The answer to the universe";AssetDatabase.CreateAsset(settings, k_MyCustomSettingsPath);AssetDatabase.SaveAssets();}return settings;}
}
class SimpleIMGUISettingsProvider : SettingsProvider
{SerializedObject m_Settings;public SimpleIMGUISettingsProvider(string path, SettingsScope scope = SettingsScope.User) : base(path, scope) { }public override void OnActivate(string searchContext, VisualElement rootElement){//当用户单击“设置”窗口中的MyCustom元素时调用m_Settings = new SerializedObject(MyCustomSettings.GetOrCreateSetting());}public override void OnDeactivate(){//用户选择了另一个设置或关闭了“设置”窗口m_Settings = null;}public override void OnFooterBarGUI(){EditorGUILayout.LabelField("FooterBar");}public override void OnTitleBarGUI(){//此按钮显示在当前选定的SettingsProvider的标题之后:if(GUILayout.Button("Help", EditorStyles.miniButton)){Debug.Log("You are on your own");}}public override void OnGUI(string searchContext){//使用IMGUI显示UI:EditorGUILayout.PropertyField(m_Settings.FindProperty("m_Number"), new GUIContent("MyNumber"));EditorGUILayout.PropertyField(m_Settings.FindProperty("m_SomeString"), new GUIContent("Some string"));}//注册SettingsProvider[SettingsProvider]public static SettingsProvider CreateMyCustomSettingsProvider(){//Editor菜单下的Preferences/MyCustomSettingsProvider菜单项SimpleIMGUISettingsProvider provider = new SimpleIMGUISettingsProvider("Preferences/MyCustomSettingsProvider", SettingsScope.User);provider.inspectorUpdateHandler += () =>{//当从Inspector更新PresetManager时,检查是否需要更新 Preset Settings Viewif(provider.m_Settings != null && provider.m_Settings.UpdateIfRequiredOrScript()){provider.Repaint();}};return provider;}
}
代码示例2:本示例说明如何基于UIElements构建SettingsProvider:需要将任何子级在OnActivate函数中添加传递给rootElement。
using UnityEditor;
using UnityEngine.UIElements;
using UnityEngine;
class MyCustomSettings:ScriptableObject
{public const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";[SerializeField] private int m_Number;[SerializeField] private string m_SomeString;internal static MyCustomSettings GetOrCreateSetting(){var settings = AssetDatabase.LoadAssetAtPath<MyCustomSettings>(k_MyCustomSettingsPath);if(settings == null){settings = ScriptableObject.CreateInstance<MyCustomSettings>();settings.m_Number = 42;settings.m_SomeString = "The answer to the universe";AssetDatabase.CreateAsset(settings, k_MyCustomSettingsPath);AssetDatabase.SaveAssets();}return settings;}
}
class SimpleIMGUISettingsProvider:SettingsProvider
{SerializedObject m_Settings;public SimpleIMGUISettingsProvider(string path, SettingsScope scope = SettingsScope.User):base(path, scope) { }public override void OnActivate(string searchContext, VisualElement rootElement){//当用户单击“设置”窗口中的MyCustom元素时调用m_Settings = new SerializedObject(MyCustomSettings.GetOrCreateSetting());//rootElement是一个VisualElement。 如果向其添加任何子级,则说明您正在使用UIElements来构建SettingsProvidervar styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/settings_ui.uss");rootElement.styleSheets.Add(styleSheet);var title = new Label(){text = "Custom UI Elements"};title.AddToClassList("title");rootElement.Add(title);var tf = new TextField(){value = m_Settings.FindProperty("m_SomeString").stringValue};tf.AddToClassList("property-value");rootElement.Add(tf);}public override void OnGUI(string searchContext){//因为UIElements正在绘制UI,所以永远不会调用此函数。}//注册SettingsProvider[SettingsProvider]public static SettingsProvider CreateMyCustomSettingsProvider(){//Preferences/MyCustomSettingsProvider菜单项SimpleIMGUISettingsProvider provider = new SimpleIMGUISettingsProvider("Preferences/MyCustomSettingsProvider", SettingsScope.User);return provider;}
}

代码示例1结果
代码示例2结果

OnDeactivate:使用此功能可为用户单击其他设置或“设置”窗口关闭时实现处理程序。
函数定义:public void OnDeactivate();
代码示例:见OnActivate代码示例1
OnFooterBarGUI:使用此功能可以使用IMGUI为SettingsProvider绘制页脚。
函数定义:public void OnFooterBarGUI();
代码示例:见OnActivate代码示例1
OnGUI:使用此功能可基于IMGUI绘制UI。假设您尚未将任何子级在OnActivate函数中添加传递给rootElement。
函数定义:public void OnGUI(string searchContext);
函数参数:
1.searchContext:“设置”窗口搜索时的匹配关键字。 用于显示或隐藏相关属性。
代码示例:见OnActivate代码示例1
OnInspectorUpdate:以每秒10帧的速度调用OnInspectorUpdate,以使检查器有机会进行更新。 有关更多详细信息,参见EditorWindow.OnInspectorUpdate。
函数定义:public void OnInspectorUpdate();
代码示例:
using UnityEditor;
using UnityEngine.UIElements;
using UnityEngine;
class MyCustomSettings : ScriptableObject
{public const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";[SerializeField] private int m_Number;[SerializeField] private string m_SomeString;internal static MyCustomSettings GetOrCreateSetting(){var settings = AssetDatabase.LoadAssetAtPath<MyCustomSettings>(k_MyCustomSettingsPath);if (settings == null){settings = ScriptableObject.CreateInstance<MyCustomSettings>();settings.m_Number = 42;settings.m_SomeString = "The answer to the universe";AssetDatabase.CreateAsset(settings, k_MyCustomSettingsPath);AssetDatabase.SaveAssets();}return settings;}
}
class SimpleIMGUISettingsProvider : SettingsProvider
{SerializedObject m_Settings;public SimpleIMGUISettingsProvider(string path, SettingsScope scope = SettingsScope.User) : base(path, scope) { }public override void OnActivate(string searchContext, VisualElement rootElement){//当用户单击“设置”窗口中的MyCustom元素时调用m_Settings = new SerializedObject(MyCustomSettings.GetOrCreateSetting());}public override void OnDeactivate(){//用户选择了另一个设置或关闭了“设置”窗口m_Settings = null;}public override void OnFooterBarGUI(){EditorGUILayout.LabelField("FooterBar");}public override void OnGUI(string searchContext){//使用IMGUI显示UI:EditorGUILayout.PropertyField(m_Settings.FindProperty("m_Number"), new GUIContent("MyNumber"));EditorGUILayout.PropertyField(m_Settings.FindProperty("m_SomeString"), new GUIContent("Some string"));}//注册SettingsProvider[SettingsProvider]public static SettingsProvider CreateMyCustomSettingsProvider(){//Editor菜单下的Preferences/MyCustomSettingsProvider菜单项SimpleIMGUISettingsProvider provider = new SimpleIMGUISettingsProvider("Preferences/MyCustomSettingsProvider", SettingsScope.User);provider.inspectorUpdateHandler += () =>{//当从Inspector更新PresetManager时,检查是否需要更新 Preset Settings View//若MyCustomSettings.asset的值在Inspector中被修改时,对应的MyCustomSettingsProvider也会同步刷新if(provider.m_Settings != null && provider.m_Settings.UpdateIfRequiredOrScript()){provider.Repaint();}};return provider;}
}
OnTitleBarGUI:使用此功能可以覆盖使用IMGUI绘制SettingsProvider的标题。 这使您可以在标题旁边添加自定义UI(例如工具栏按钮)。 AssetSettingsProvider使用此机制来显示“添加到预设”和“帮助”按钮。
函数定义:public void OnTitleBarGUI();
代码示例:见OnActivate代码示例1
Repaint:请求SettingsWindow进行重画。
函数定义:public void Repaint();

  (4) Public Methods

GetSearchKeywordsFromGUIContentProperties:从特定类型的所有公共静态成员中提取搜索关键字。
函数定义:public static IEnumerable<string> GetSearchKeywordsFromGUIContentProperties();
函数返回值:
1IEnumerable<string>:返回从静态GUIContent提取的关键字列表。
代码示例:
using UnityEditor;
using UnityEngine.UIElements;
using UnityEngine;
class MyCustomSettings : ScriptableObject
{public const string k_MyCustomSettingsPath = "Assets/Editor/MyCustomSettings.asset";[SerializeField] private int m_Number;[SerializeField] private string m_SomeString;internal static MyCustomSettings GetOrCreateSetting(){var settings = AssetDatabase.LoadAssetAtPath<MyCustomSettings>(k_MyCustomSettingsPath);if (settings == null){settings = ScriptableObject.CreateInstance<MyCustomSettings>();settings.m_Number = 42;settings.m_SomeString = "The answer to the universe";AssetDatabase.CreateAsset(settings, k_MyCustomSettingsPath);AssetDatabase.SaveAssets();}return settings;}internal static SerializedObject GetSerializedSettings(){return new SerializedObject(GetOrCreateSetting());}
}
class SimpleIMGUISettingsProvider : SettingsProvider
{public SimpleIMGUISettingsProvider(string path, SettingsScope scope = SettingsScope.User) : base(path, scope) { }[SettingsProvider]public static SettingsProvider CreateFromFilePath(){//从文件路径创建AssetSettingsProvider:var provider = AssetSettingsProvider.CreateProviderFromAssetPath("Project/AssetSettings/FromFile", MyCustomSettings.k_MyCustomSettingsPath);//在特定路径下从序列化对象的属性中注册关键字provider.keywords = SettingsProvider.GetSearchKeywordsFromPath(MyCustomSettings.k_MyCustomSettingsPath);//输出:Script Number Some String//foreach (string key in provider.keywords)//{//    Debug.LogError(key);//}return provider;}[SettingsProvider]public static SettingsProvider CreateFromSettingsObject(){//从设置对象(UnityEngine.Object)创建AssetSettingsProvider:var settingsObj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(MyCustomSettings.k_MyCustomSettingsPath);var provider = AssetSettingsProvider.CreateProviderFromObject("Project/AssetSettings/FromObject", settingsObj);//从settingsObj属性注册关键字provider.keywords = SettingsProvider.GetSearchKeywordsFromSerializedObject(new SerializedObject(settingsObj));//输出:Script Number Some String//foreach (string key in provider.keywords)//{//    Debug.LogError(key);//}return provider;}class Styles{public static GUIContent number = new GUIContent("My Number");public static GUIContent someString = new GUIContent("Some string");}[SettingsProvider]public static SettingsProvider CreateFromSettingsFromFunctor(){//从必须返回UnityEngine.Object的函数创建一个AssetSettingsProvider:var provider = new AssetSettingsProvider("Project/AssetSettings/FromFunctor", () => Editor.CreateEditor(AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(MyCustomSettings.k_MyCustomSettingsPath)));//在Styles类中从静态GUIContent注册关键字provider.keywords = SettingsProvider.GetSearchKeywordsFromGUIContentProperties<Styles>();//输出:Number Some String//foreach (string key in provider.keywords)//{//    Debug.LogError(key);//}return provider;}
}

代码示例结果

GetSearchKeywordsFromPath:从资产的序列化属性中的特定路径中提取搜索关键字。
函数定义:public static IEnumerable<string> GetSearchKeywordsFromPath(string path);
函数参数:path:资产在磁盘上的路径。
函数返回值:
IEnumerable<string>:返回关键字列表
代码示例:见GetSearchKeywordsFromGUIContentProperties
GetSearchKeywordsFromSerializedObject:从SerializedObject的序列化属性中提取搜索关键字。
函数定义:public static IEnumerable<string> GetSearchKeywordsFromSerializedObject(SerializedObject serializedObject);
函数参数:serializedObject	Object to extract properties from.

  参考资料
  1.MenuItem:https://docs.unity3d.com/ScriptReference/MenuItem.html
  2.ScriptableObject:https://docs.unity3d.com/2018.3/Documentation/ScriptReference/ScriptableObject.html
  3.SettingsProvider:https://docs.unity3d.com/2019.3/Documentation/ScriptReference/SettingsProvider.html

这篇关于Unity流水账11:编辑器工具总结(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/464740

相关文章

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

Kubernetes常用命令大全近期总结

《Kubernetes常用命令大全近期总结》Kubernetes是用于大规模部署和管理这些容器的开源软件-在希腊语中,这个词还有“舵手”或“飞行员”的意思,使用Kubernetes(有时被称为“... 目录前言Kubernetes 的工作原理为什么要使用 Kubernetes?Kubernetes常用命令总

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

基于C#实现PDF文件合并工具

《基于C#实现PDF文件合并工具》这篇文章主要为大家详细介绍了如何基于C#实现一个简单的PDF文件合并工具,文中的示例代码简洁易懂,有需要的小伙伴可以跟随小编一起学习一下... 界面主要用于发票PDF文件的合并。经常出差要报销的很有用。代码using System;using System.Col

redis-cli命令行工具的使用小结

《redis-cli命令行工具的使用小结》redis-cli是Redis的命令行客户端,支持多种参数用于连接、操作和管理Redis数据库,本文给大家介绍redis-cli命令行工具的使用小结,感兴趣的... 目录基本连接参数基本连接方式连接远程服务器带密码连接操作与格式参数-r参数重复执行命令-i参数指定命

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

Python pyinstaller实现图形化打包工具

《Pythonpyinstaller实现图形化打包工具》:本文主要介绍一个使用PythonPYQT5制作的关于pyinstaller打包工具,代替传统的cmd黑窗口模式打包页面,实现更快捷方便的... 目录1.简介2.运行效果3.相关源码1.简介一个使用python PYQT5制作的关于pyinstall

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的