Unity Odin从入门到精通(二):创建编辑器窗口「建议收藏」

Unity Odin从入门到精通(二):创建编辑器窗口「建议收藏」前言:为了更加快速和高效的组织项目数据,开发者可以使用Odin来快速创建自定义编辑器窗口,以帮助组织项目数据。这就是Odin可以真正帮助提升工作流程的地方。

大家好,又见面了,我是你们的朋友全栈君。

前言:开发者可以使用Odin来快速地创建编辑器窗口,从而更加高效的组织项目中的数据。

OdinEditorWindow:它是Odin中创建编辑器窗口的基类。具有以下特性:
1.主要作用:如下所示:
1.1.开发者通过继承该类就可以在不用编写任何编辑器GUI代码的情况下,在编辑器窗口中呈现字段、属性和方法。
2.包含父类:如下所示:
2.1.EditorWindow:它是Unity中创建编辑器窗口的基类。当继承自该类时,Odin就具有Unity编辑器窗口中所有的功能。
2.2.ISerializationCallbackReceiver:它是Unity中进行序列化&反序列化游戏类型对象时,调用回调函数的接口。
3.包含属性:如下所示:
3.1.CurrentDrawingTargets:当前正在绘制的目标实例列表。
3.2.DefaultEditorPreviewHeight:默认的编辑器窗口预览高度。
3.3.DefaultLabelWidth:默认的标签文本宽度,其中 0 ~ 1 表示百分比,> 1 表示像素值。
3.4.WindowPadding:编辑器窗口填充的四维向量(x = 左,y = 右,z = 顶部,w = 底部),其中每个维度对应的真实填充值最终会大于或者等于该维度值。
3.5.UseScrollView:编辑器窗口是否(true:是 false:否)应该绘制滚动视图。
3.6.DrawUnityEditorPreview:编辑器窗口是否(true:是 false:否)应该在可能的情况下绘制Unity编辑器窗口预览。
4.包含函数:如下所示:
4.1.CreateOdinEditorWindowInstanceForObject:对指定的目标实例创建一个默认不打开的编辑器窗口实例。
4.2.OnEnable:当编辑器窗口被启用时,就会调用该函数。
4.3.Initialize:当编辑器窗口被初始化时,就会调用该函数。
4.4.OnGUI:当编辑器窗口被绘制时,就会调用该函数。
4.5.GetTarget:获取想要绘制的目标实例。具有以下特性:
4.5.1.目标实例可以是任何类型的实例。
4.5.2.默认情况下,目标实例为编辑器窗口本身。
4.6.GetTargets:获取想要绘制的目标实例列表。具有以下特性:
4.6.1.默认情况下,该函数内部会调用GetTarget函数来获取一个目标实例。
4.7.OnBeginDrawEditors:该函数会在绘制目标实例列表之前被调用。
4.8.DrawEditors:当绘制目标实例列表时,就会调用该函数。
4.9.DrawEditor:当绘制指定索引的目标实例时,就会调用该函数。
4.10.DrawEditorPreview:当DrawUnityEditorPreview属性值为true时,就会为指定索引的目标实例绘制一个指定高度的Unity编辑器窗口预览。
4.11.OnEndDrawEditors:该函数会在绘制目标实例列表之后被调用。
4.12.OnBeforeSerialize:当Unity序列化游戏类型对象之前,就会调用该回调函数。
4.13.OnAfterDeserialize:当Unity反序列化游戏类型对象之后,就会调用该回调函数。
4.14.OnDestroy:当编辑器窗口被销毁时,就会调用该函数。
4.15.EnsureEditorsAreReady:确保编辑器窗口一定进行了初始化和绘制过程。
4.16.InspectObject(OdinEditorWindow window, Object obj):在指定的编辑器窗口实例中检测并绘制指定的目标实例。
4.17.InspectObject(Object obj):对指定的目标实例创建一个默认打开的编辑器窗口实例。
4.18.InspectObjectInDropDown:对指定的目标实例创建一个默认打开的编辑器窗口实例。具有以下特性:
4.18.1.该编辑器窗口实例被放置在一个下拉窗口中。
4.18.2.该编辑器窗口实例在丢失焦点时会执行关闭操作。
5.包含事件:如下所示:
5.1.OnClose:关闭编辑器窗口时,就会调用该事件。
5.2.OnBeginGUI:开始调用OnGUI函数时,就会调用该事件。
5.3.OnEndGUI:结束调用OnGUI函数时,就会调用该事件。
6.创建编辑器窗口的流程:如下所示:
6.1.首先创建一个C#脚本文件;然后在该脚本文件里面使用UNITY_EDITOR宏来包含脚本代码,从而让该脚本代码只有在编辑器环境下才起作用。
6.2.首先创建一个编辑器窗口类型;然后让该编辑器窗口类型继承自OdinEditorWindow类型。
6.3.首先在编辑器窗口类型中提供一个私有静态的OpenWindow函数;接着将MenuItemAttribute定制特性应用到该OpenWindow函数上,从而可以在Unity的菜单栏里面显示一个指定名称的菜单项;然后在该OpenWindow函数里面通过调用GetWindow<OdinEditorWindow派生类型>函数来获取编辑器窗口实例;最后通过该编辑器窗口实例调用Show函数来绘制目标实例。
6.4.首先重写编辑器窗口类型中的GetTarget函数;然后在该GetTarget函数里面提供一个想要被绘制的目标实例。如果目标实例就是编辑器窗口本身的话,就可以不用重写该GetTarget函数。
6.5.在目标实例的类型里面利用可序列化类型来设计编辑器窗口。
6.6.在目标实例的类型里面利用Odin和Unity当中提供的所有定制特性来设计编辑器窗口。
6.7.在Unity菜单栏中点击对应的菜单项来打开编辑器窗口。

OdinMenuEditorWindow:它是Odin中创建菜单树编辑器窗口的基类。具有以下特性:
1.包含属性:如下所示:
1.1.MenuWidth:设置菜单项的宽度像素值等于2乘以该参数值(默认为180)。
1.2.ResizableMenuWidth:是否(true:是 false:否)可以动态调整菜单项的宽度像素值。
1.3.MenuTree:获取编辑器窗口实例关联的菜单树实例。
1.4.DrawMenuSearchBar:是否(true:是 false:否)绘制菜单搜索栏。经测试,该属性存在BUG,但是可以通过MenuTree.Config.DrawSearchToolbar字段进行正确的设置。
1.5.CustomSearchFunction:设置菜单搜索栏的搜索函数。经测试,该属性存在BUG,但是可以通过MenuTree.Config.SearchFunction字段进行正确的设置。
2.包含函数:如下所示:
2.1.BuildMenuTree:创建菜单树实例。
2.2.ForceMenuTreeRebuild:重建菜单树实例。
2.3.OnGUI:当编辑器窗口被绘制时,就会调用该函数。
2.4.DrawMenu:绘制菜单树实例。
2.5.OnDestroy:当编辑器窗口被销毁时,就会调用该函数。
2.6.TrySelectMenuItemWithObject:尝试选择具有指定对象的菜单项。
3.创建菜单树编辑器窗口的流程:如下所示:
3.1.首先创建一个C#脚本文件;然后在该脚本文件里面使用UNITY_EDITOR宏来包含脚本代码,从而让该脚本代码只有在编辑器环境下才起作用。
3.2.首先创建一个菜单树编辑器窗口类型;然后让该菜单树编辑器窗口类型继承自OdinMenuEditorWindow类型。
3.3.首先在菜单树编辑器窗口类型里面重写BuildMenuTree函数;然后在该BuildMenuTree函数里面返回一个包含菜单项列表的菜单树实例。
3.4.首先在菜单树编辑器窗口类型中提供一个私有静态的OpenWindow函数;接着将MenuItemAttribute定制特性应用到该OpenWindow函数上,从而可以在Unity的菜单栏里面显示一个指定名称的菜单项;然后在该OpenWindow函数里面通过调用GetWindow<OdinMenuEditorWindow派生类型>函数来获取菜单树编辑器窗口实例;最后通过该菜单树编辑器窗口实例调用Show函数来绘制菜单树实例。
3.5.在Unity菜单栏中点击对应的菜单项来打开菜单树编辑器窗口。

OdinMenuItem:它是Odin中表示具有一个或者多个对象的菜单项。具有以下特性:
1.包含字段:如下所示:
1.1.MenuItemIsBeingRendered:是否(true:是 false:否)已经绘制菜单项。
1.2.DefaultToggledState:菜单项的默认切换状态。其中,true表示展开状态,false表示收缩状态。经测试,该字段存在BUG,但是可以通过Toggled属性进行正确的设置。
2.包含事件:如下所示:
2.1.OnDrawItem:当OnDrawMenuItem函数调用完毕后,就会调用该事件。
2.2.OnRightClick:当用户右键单击菜单项时,就会调用该事件。
3.包含属性:如下所示:
3.1.Name:菜单项的原始名称。
3.2.SmartName:菜单项的智能名称。当Name属性值为null或者$时,SmartName属性值就等于菜单项具有的对象通过调用ToString函数来获取的返回值;否则SmartName属性值就等于Name属性值。
3.3.IsSelected:在菜单树中是否(true:是 false:否)选中了该菜单项。
3.4.MenuTree:获取菜单项所在的菜单树。
3.5.Value:菜单项具有的对象。
3.6.SearchString:菜单项的搜索字符串,主要用来在菜单树的搜索框中检索菜单项。
3.7.Rect:菜单项的矩形区域(包含坐标和大小)。
3.8.PrevVisualMenuItem:获取菜单项的上一个可视菜单项。如果获取不到的话,那么属性值就为null。
3.9.NextVisualMenuItem:获取菜单项的下一个可视菜单项。如果获取不到的话,那么属性值就为null。
3.10.Parent:获取菜单项的父级菜单项。如果获取不到的话,那么属性值就为null。
3.11.LabelRect:菜单项的绘制名称的矩形区域(包含坐标和大小)。
3.12.IconSelected:选择菜单项时显示的图标。
3.13.Icon:不选择菜单项时显示的图标。
3.14.IconGetter:获取菜单项图标的委托。默认情况下,当菜单项被选择时,调用该委托就会返回IconSelected属性值;否则,调用该委托就会返回Icon属性值。
3.15.FlatTreeIndex:获取菜单项的索引位置。
3.16.ChildMenuItems:获取菜单项的子菜单项列表。
3.17.Toggled:菜单项的切换状态。其中,true表示展开状态,false表示收缩状态。
3.18.Style:菜单项的样式。如果设置成null的话,那么在获取该属性值时就会返回OdinMenuTree类型的DefaultMenuStyle属性值;否则,在获取该属性值时就会返回设置的数值。
4.包含函数:如下所示:
4.1.Deselect:取消选择菜单项。如果该菜单项本身没有被选择的话,那么该函数就会返回false;否则,该函数就会返回true。
4.2.Select:选择菜单项。如果参数值为false的话,那么该函数就会先清空选择列表,然后将菜单项添加到选择列表中;否则,就只是将菜单项添加到选择列表中。
4.3.GetFullPath:获取菜单项的全路径。
4.4.GetChildMenuItemsRecursive:使用深度优先搜索算法来递归获取当前菜单项下面的子菜单项列表。其中,如果参数值为true,那么子菜单项列表中就包含当前菜单项;否则子菜单项列表中就不包含当前菜单项。
4.5.GetParentMenuItemsRecursive:使用深度优先搜索算法来递归获取当前菜单项上面的父菜单项列表。其中,如果includeSelf参数值为true或者当前菜单项不存在父菜单项且includeRoot参数值为true时,那么父菜单项列表中就包含当前菜单项;否则父菜单项列表中就不包含当前菜单项。
4.6.DrawMenuItems:该函数内部通过调用DrawMenuItem函数来绘制该菜单项及其所有子菜单项。其中,菜单项用到的缩进等级就是参数值;子菜单项用到的缩进等级就是参数值加一。
4.7.DrawMenuItem:用指定的缩进等级来绘制菜单项。
4.8.OnDrawMenuItem:当菜单项完成绘制之后且菜单项鼠标事件处理之前,就会调用该函数来将自定义GUI添加到菜单项中。
4.9.HandleMouseEvents:当OnDrawItem事件调用完毕后,就会调用该函数来处理菜单项鼠标事件。

OdinMenuStyle:它是Odin中菜单项使用的样式设置。具有以下特性:
1.包含字段:如下所示:
1.1.Height:设置菜单项的高度。
1.2.Offset:设置菜单项内容的全局水平偏移值。
1.3.LabelVerticalOffset:设置菜单项中标签文本的垂直偏移值。当偏移值大于0时,标签文本就向下偏移;当偏移值小于0时,标签文本就向上偏移;当偏移值等于0时,标签文本就不偏移。
1.4.IndentAmount:该字段只有应用到OdinMenuTree.DefaultMenuStyle属性时才有效。用来设置每一层级菜单项的缩进像素值。
1.5.IconSize:设置菜单项中图标的大小。
1.6.IconOffset:设置菜单项中图标的水平偏移值。
1.7.NotSelectedIconAlpha:设置菜单项中图标在未选择状态下的透明度。
1.8.IconPadding:设置菜单项中图标和标签文本之间的填充值。
1.9.DrawFoldoutTriangle:当该字段值为true并且菜单项存在子菜单项时,就会在菜单项上绘制一个折叠三角形。否则,就不会在菜单项上绘制一个折叠三角形。
1.10.TriangleSize:设置菜单项中折叠三角形的大小。
1.11.TrianglePadding:设置菜单项中折叠三角形与标签文本之间的填充值。
1.12.AlignTriangleLeft:当该字段值为true时,菜单项中折叠三角形就位于菜单项的左侧;否则,菜单项中折叠三角形就位于菜单项的右侧。
1.13.Borders:该字段只有应用到OdinMenuTree.DefaultMenuStyle属性时才有效。当该字段值为true时,就会在菜单项之间绘制边框;否则,就不会在菜单项之间绘制边框。
1.14.BorderPadding:该字段只有应用到OdinMenuTree.DefaultMenuStyle属性时才有效。用来设置边框的水平填充值。
1.15.BorderAlpha:该字段只有应用到OdinMenuTree.DefaultMenuStyle属性时才有效。用来设置边框的透明度。
1.16.SelectedColorDarkSkin:设置菜单项选中时的背景色。
1.17.SelectedInactiveColorDarkSkin:该字段经过测试发现不起效果。
1.18.SelectedColorLightSkin:该字段经过测试发现不起效果。
1.19.SelectedInactiveColorLightSkin:该字段经过测试发现不起效果。
2.包含属性:如下所示:
2.1.DefaultLabelStyle:设置菜单项中标签文本在未选择状态下的文本样式。
2.2.SelectedLabelStyle:设置菜单项中标签文本在选择状态下的文本样式。
2.3.TreeViewStyle:获取一个Unity窗口风格的菜单项样式。
3.包含函数:如下所示:
3.1.Clone:将当前的样式设置克隆一份出来。
3.2.CopyCSharpSnippet:当前的样式设置作为菜单项被添加到菜单树中时,就会显示一个名称为”Copy C# Snippet”的按钮。当用户点击该按钮时,首先会将当前的样式设置以代码段的形式复制到剪切面板当中,然后用户就可以将剪切的代码段粘贴到代码文件当中。

OdinMenuTree:它是Odin中的菜单树类型。该类型既可以单独使用,又可以和OdinMenuEditorWindows类型配合使用。可以通过该类型来操作菜单项以及处理键盘导航。具有以下特性:
1.包含字段:如下所示:
1.1.ActiveMenuTree:获取当前处于活动状态的菜单树。
1.2.FlatMenuTree:获取搜索菜单项列表。
2.包含属性:如下所示:
2.1.Config:设置菜单树的默认绘制配置。如:菜单搜索栏,滚动视图,键盘导航,双击回调,菜单项样式等。
2.2.DefaultMenuStyle:设置菜单树中所有菜单项的默认样式配置。
2.3.DrawInSearchMode:当搜索词为空串时,该属性值就会false。否则,该属性值就为true。
2.4.RootMenuItem:获取根菜单项。
2.5.MenuItems:获取根菜单项下面的子菜单项列表。
2.6.Selection:获取菜单树的选择配置。
3.包含函数:如下所示:
3.1.Add(String path, Object instance):在指定路径添加具有指定对象实例的菜单项。
3.2.Add(String path, Object instance, EditorIcon / Sprite / Texture icon):在指定路径添加具有指定对象实例和图标的菜单项。
3.3.AddRange:首先遍历指定对象实例集合;然后获取对象实例的路径和图标;最后在该路径添加具有该对象实例和图标的菜单项。
3.4.DrawMenuTree:递归绘制菜单树,一般在菜单树被单独使用时才去调用该函数。
3.5.DrawSearchToolbar:绘制菜单搜索栏。经测试貌似不起效果。
3.6.EnumerateTree(Action action):使用深度优先搜索算法来将根菜单项下面的每一个子菜单项都以参数的形式传递给指定的回调函数。
3.7.EnumerateTree(Action<OdinMenuItem, bool> action, bool includeRootNode):首先使用深度优先搜索算法和是否(true:是 false:否)包含根菜单项参数来将菜单树下面满足条件的每一个子菜单项都以参数的形式传递给指定的回调函数。然后将回调函数结果值为true的菜单项以列表的形式返回。
3.8.HandleKeyboardMenuNavigation:处理键盘菜单导航以防止菜单树从其他文本字段中窃取输入事件。
3.9.MarkDirty:将菜单树的状态标记为脏,从而可以在下一帧调用UpdateMenuTree函数。
3.10.UpdateMenuTree:该函数可以手动或者自动调用,主要用来更新菜单树。
3.11.ScrollToMenuItem:将指定的菜单项滚动到可视区域的中间或者底部位置。

OdinMenuTreeExtensions:它是Odin中具有OdinMenuTree类型和OdinMenuItem类型扩展函数的类。包含的扩展函数如下所示:
1.AddThumbnailIcon(this OdinMenuItem item, bool preferAssetPreviewAsIcon):用来设置菜单项的显示图标。当菜单项具有的对象为UnityEngine.Object类型或者System.Type类型时,如果preferAssetPreviewAsIcon参数值为false时,那么该函数就设置Icon属性值;否则,该函数就设置IconGetter属性值。当菜单项具有的对象为字符串类型,如果该字符串为某个文件路径或者某个目录路径,那么该函数就设置Icon属性值;否则就什么也不做处理。
2.AddThumbnailIcons(this IEnumerable menuItems, bool preferAssetPreviewAsIcon):首先遍历菜单项列表中每一个菜单项。然后将该菜单项作为参数,并结合preferAssetPreviewAsIcon参数一起来调用AddThumbnailIcon函数,进而完成菜单项设置显示图标的工作。
3.GetMenuItem:获取指定路径的菜单项。
4.AddMenuItemAtPath:首先在指定的路径下添加指定的菜单项。然后返回新创建的菜单项列表。
5.AddAssetAtPath:首先获取指定的资源路径和资源类型对应的对象实例。接着创建一个具有该对象实例的菜单项。然后在指定的路径下添加该菜单项。最后返回新创建的菜单项列表。
6.AddAllAssetsAtPath(this OdinMenuTree tree, string menuPath, string assetFolderPath, System.Type type, bool includeSubDirectories, bool flattenSubDirectories):首先当includeSubDirectories参数值为false时,就遍历指定的资源路径;否则就遍历指定的资源路径及其里面的子目录。接着根据查找到的资源文件和指定的资源类型来创建对象实例,并创建一个拥有该对象实例的菜单项。然后当flattenSubDirectories参数值为true时,就在指定的路径下面添加该菜单项;否则就在新路径(指定的路径加上资源路径下面的子目录路径)下面添加该菜单项。最后返回新创建的菜单项列表。
7.AddAllAssetsAtPathCombined(this OdinMenuTree tree, string menuPath, string assetFolderPath, Type type, bool includeSubDirectories):首先当includeSubDirectories参数值为false时,就遍历指定的资源路径;否则就遍历指定的资源路径及其里面的子目录。接着根据查找到的资源文件和指定的资源类型来创建对象实例,并将该对象实例添加到一个列表中。然后创建一个具有该列表的菜单项。最后在指定的路径下面添加该菜单项,并返回新创建的菜单项列表。
8.AddObjectAtPath(this OdinMenuTree tree, string menuPath, object instance, bool forceShowOdinSerializedMembers):在指定的路径下添加具有指定对象实例的菜单项。如果指定对象实例的类型是字典或者泛型的话,可以通过forceShowOdinSerializedMembers参数来控制是否(true:是 false:否)将指定对象实例序列化显示到窗口上。
9.SortMenuItemsByName(this OdinMenuTree tree, bool placeFoldersFirst):首先获取菜单树的菜单项列表。然后调用SortMenuItemsByName(this IEnumerable menuItems, bool placeFoldersFirst, bool ignoreLeadingZeroes, bool ignoreWhiteSpace, bool ignoreCase)函数来完成菜单项列表的排序工作。
10.SortMenuItemsByName(this IEnumerable menuItems, bool placeFoldersFirst, bool ignoreLeadingZeroes, bool ignoreWhiteSpace, bool ignoreCase):首先创建一个比较函数。然后调用SortMenuItemsByName(this IEnumerable menuItems, Comparison comparison)函数来完成菜单项列表的排序工作。其中,比较函数的执行流程大致为:当placeFoldersFirst参数值为true时,首先就会对菜单项列表按照菜单项是否含有子菜单项来排序,然后再按照菜单项的名称进行排序。当placeFoldersFirst参数值为false时,就会对菜单项列表按照菜单项的名称进行排序。当按照菜单项的名称进行排序时还会根据ignoreLeadingZeroes参数值来判定是否(true:是 false:否)忽略前导零;根据ignoreWhiteSpace参数值来判定是否(true:是 false:否)忽略空白;根据ignoreCase参数值来判定是否(true:是 false:否)忽略大小写。
11.SortMenuItemsByName(this IEnumerable menuItems, Comparison comparison):对指定的菜单项列表按照指定的比较函数来进行排序处理。
12.AddIcon(this IEnumerable menuItems, Texture / EditorIcon / Sprite icon):内部调用AddIcon(this IEnumerable menuItems, Texture icon, Texture iconSelected)函数来完成菜单项列表中最后一个菜单项的设置图标操作。
13.AddIcon(this IEnumerable menuItems, Texture icon, Texture iconSelected):首先获取菜单项列表中最后的一个菜单项。然后设置该菜单项的选择图标为iconSelected参数值,非选择图标为icon参数值。
14.AddIcons(this IEnumerable menuItems, EditorIcon icon):首先遍历菜单项列表中的每一个菜单项。然后设置该菜单项的选择图标为参数icon.Raw,非选择图标为参数icon.Highlighted。
15.AddIcons(this IEnumerable menuItems, Texture icon):首先遍历菜单项列表中的每一个菜单项。然后设置该菜单项的非选择图标为icon参数值。
16.AddIcons(this IEnumerable menuItems, Texture icon, Texture iconSelected):首先遍历菜单项列表中的每一个菜单项。然后设置该菜单项的选择图标为iconSelected参数值,非选择图标为icon参数值。
17.AddIcons(this IEnumerable menuItems, Func<OdinMenuItem, Sprite> / Func<OdinMenuItem, Texture> getIcon):首先遍历菜单项列表中的每一个菜单项。然后将该菜单项作为参数来调用getIcon参数值代表的委托,进而获取一个图标实例。最后创建一个返回该图标实例的委托,并设置成该菜单项获取图标的委托。
18.AddIcons(this IEnumerable menuItems, Func<T, Sprite> / Func<T, Texture> getIcon):首先遍历菜单项列表中的每一个菜单项。然后当该菜单项具有的对象为空或者类型不为T的话就直接跳过;否则就将该菜单项具有的对象作为参数来调用getIcon参数值代表的委托,进而获取一个图标实例。最后创建一个返回该图标实例的委托,并设置成该菜单项获取图标的委托。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/162828.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号