Unity编辑器拓展-Odin

这篇具有很好参考价值的文章主要介绍了Unity编辑器拓展-Odin。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.相比于原生Unity的优势

  • Unity不支持泛型类型序列化,例如字典原生Unity不支持序列化,而Odin可以继承序列化的Mono实现
  • 功能强大且使用简单,原生Unity想实现一些常见的功能需要额外自己编写Unity扩展的编码,实现功能只需要加一个特性即可Odin帮忙写好了内部管理和实现
  • 编辑器的窗口实现简单且美观

2.常用功能代码总结

通过Tools-Odin Inspector-Attribute Overview即可打开一个预览各个特性的效果的窗口,可供参考

OdinValueDrawer

类继承自OdinValueDrawer,其中T为自定义数据类型,之后重写DrawPropertyLayout方法,实现自定义绘制,实现了对于我们自定义数据类型的自定义绘制,重写Initialize来做对其下序列化部分的初始化,例如Selector的生成,选择变化的事件监听,初始值的定义。同时在DrawPropertyLayout中定义对应的按钮,在按下的时候用selector.ShowInPopup();打开对应的selector

#if UNITY_EDITOR
namespace Sirenix.OdinInspector.Demos
{
    using UnityEngine;
    using System;
 
#if UNITY_EDITOR
 
    using Sirenix.OdinInspector.Editor;
    using UnityEditor;
    using Sirenix.Utilities;
 
#endif
 
    // 演示如何为自定义类型生成自定义drawer的示例。
    [TypeInfoBox("此示例演示如何为自定义结构或类实现自定义drawer")]
    public class CustomDrawerExample : MonoBehaviour
    {
        public MyStruct MyStruct;
        [ShowInInspector]
        public static float labelWidth = 10;
    }
 
    // 自定义数据结构,用于演示。
    [Serializable]
    public struct MyStruct
    {
        public float X;
        public float Y;
    }
 
#if UNITY_EDITOR
 
    public class CustomStructDrawer : OdinValueDrawer<MyStruct>
    {
        protected override void DrawPropertyLayout(GUIContent label)
        {
            //获取我们绘制类的值
            MyStruct value = this.ValueEntry.SmartValue;
 
            //获取要绘制的区域(rect)
            var rect = EditorGUILayout.GetControlRect();
            //在Odin中,标签是可选项,可以为空,所以我们必须考虑到这一点。
            if (label != null)
            {
                rect = EditorGUI.PrefixLabel(rect, label);
            }
 
            //保存原始labelWidth的宽度,此label为struct中对应的X,Y
            var prev = EditorGUIUtility.labelWidth;
 
            //设定新的label宽度
            EditorGUIUtility.labelWidth = CustomDrawerExample.labelWidth;
 
            //根据slider对应的值进行赋值
            value.X = EditorGUI.Slider(rect.AlignLeft(rect.width * 0.5f), "X", value.X, 0, 1);
            value.Y = EditorGUI.Slider(rect.AlignRight(rect.width * 0.5f), "Y", value.Y, 0, 1);
 
            //恢复设定原始label宽度
            EditorGUIUtility.labelWidth = prev;
 
            //将新的Struct赋值给我们定义的MyStruct
            this.ValueEntry.SmartValue = value;
        }
    }
#endif
}
#endif
 

OdinSelector

一个选择框,可以选择提供的列表,同时选择后触发对应的事件

BuildSelectionTree

BuildSelectionTree的作用是在OdinSelector中构建一个选择树,也就是显示在弹出窗口中的树形结构的列表。你可以通过重写这个方法,来决定选择树中包含哪些值,以及它们的层级关系和排序方式。

protected override void BuildSelectionTree(OdinMenuTree tree)  
{  
//搜索框
    tree.Config.AutoFocusSearchBar = true;  
    tree.Config.DrawSearchToolbar = true;  
    tree.Selection.SupportsMultiSelect = false;  
  
    tree.MenuItems.Clear();  
    foreach (结合excel枚举对应的pb)  
    {      tree.Add(path, instance);
    }}

在外部进行的初始化

例如在上述的Drawer的Init中进行初始化,需要new出这个类,并且增加监听事件,且设置初始值。同时监听外部按钮,打开这个selector

m_WeaponIDSelector = new WeaponIDSelector();  
m_WeaponIDSelector.SelectionTree.UpdateMenuTree();  
m_WeaponIDSelector.SetSelection(WeaponData.weaponKey.thingID); //初始值 
m_WeaponIDSelector.SelectionChanged += OnWeaponThingIDChanged;//改变时候监听
// 重写Initialize方法
protected override void Initialize()
{
// 调用基类的Initialize方法
base.Initialize();

// 实例化OdinMenuTree对象
tree = new OdinMenuTree();

// 添加一些菜单项到选择树中,例如一些GameObject或者其他自定义对象
tree.Add("Cube", GameObject.CreatePrimitive(PrimitiveType.Cube));
tree.Add("Sphere", GameObject.CreatePrimitive(PrimitiveType.Sphere));
tree.Add("MyObject", new MyObject());

// 设置选择树的配置,例如是否支持多选,是否显示搜索栏等
tree.Config.DrawSearchToolbar = true;
tree.Config.MultiSelect = true;

// 设置选择树的事件,例如当菜单项被选中或者双击时执行一些操作
tree.Selection.SelectionChanged += OnSelectionChanged;
tree.MenuItems.OnDoubleClick += OnDoubleClick;

// 在Initialize的时候调用UpdateMenuTree方法,以便初始化选择树中的菜单项,以及处理搜索和排序等功能
tree.UpdateMenuTree();
}

在外部按钮按下进行的显示这个selector

//FocusType是一个枚举类型,用于表示按钮是否可以通过键盘选择。FocusType有三个可能的值:Passive、Keyboard和Native.Passive表示按钮不会接收键盘焦点,只能通过鼠标点击选择;Keyboard表示按钮可以通过Tab键或方向键在其他控件之间切换焦点;Native表示按钮使用平台本地的焦点行为,例如在Mac上使用Option+Tab键切换焦点.在你的代码中,FocusType.Passive表示你的下拉按钮不需要通过键盘选择,只能通过鼠标点击打开下拉菜单。
if (EditorGUILayout.DropdownButton(new GUIContent("武器选择: " + m_WeaponIDSelector.CurSelectName), FocusType.Passive))  
{  
    m_WeaponIDSelector.RebuildSelectionTree();  
    m_WeaponIDSelector.EnsureSingleClickToSelect();  
    m_WeaponIDSelector.ShowInPopup();  
}
public void RebuildSelectionTree()  
{  
    List<uint> curSelections = GetCurrentSelection().ToList();  
    BuildSelectionTree(SelectionTree);  
    EnableIDChangeEvent = false;  
    SetSelection(curSelections);  
    EnableIDChangeEvent = true;  
    SelectionTree.Config.AutoFocusSearchBar = true;  
}
public void EnsureSingleClickToSelect()  
{  
//设置选择树的Config.SelectionConfirmNavigationKey属性为KeyCode.None,这样就可以取消双击确认选择的功能
    EnableSingleClickToSelect();  
    //设置了SelectionTree.Config.ConfirmSelectionOnDoubleClick属性为false,这个属性也是用于控制是否需要双击确认选择的功能虽然这个属性和Config.SelectionConfirmNavigationKey属性有重复的作用,但是为了保险起见,最好都设置一下。
    SelectionTree.Config.ConfirmSelectionOnDoubleClick = false;  
    //设置了SelectionTree.Config.AutoFocusSearchBar属性为true,这个属性可以让选择树在打开时自动聚焦搜索栏,方便用户输入搜索关键词
    SelectionTree.Config.AutoFocusSearchBar = true;  
}

处理Selector的改变

这里需要注意的是要用var first = col.FirstOrDefault(); 来取,并且需要做判空,一般是取完keyID之后再去读表刷上其他的数据,或者是根据

selector.SelectionChanged += col => //添加SelectionChanged事件的处理方法
{
var first = col.FirstOrDefault(); //获取第一个选择的对象
if (first != null) //如果不为空
{
selectedName = first.name; //更新selectedName为对象的名称
}

缩进级别

  • GUIHelper.PushIndentLevel(1);
  • GUIHelper.PopIndentLevel();
    结合使用,增加一个缩进级别,可以让GUI的元素更加有层次感和结构化。例如,你可以用这个方法来创建一个树形的菜单或列表。

结构化API

  • EditorGUILayout.BeginHorizontal();这两个老朋友了就不解释了
  • EditorGUILayout.BeginVertical();
  • GUIHelper.PushGUIEnabled(bool);//表示接下来的一个范围内我要检查一下这个bool值来觉得这些UI是否可以被选
  • GUIHelper.PopGUIEnabled();
//GUIHelper.PushGUIEnabled和GUIHelper.PopGUIEnabled是两个用于控制GUI元素是否可用的方法。它们的作用是在一段代码中临时改变GUI元素的可用状态,而不影响其他代码中的GUI元素。具体来说,GUIHelper.PushGUIEnabled方法可以接受一个布尔值作为参数,表示要设置的GUI元素的可用状态。这个方法会将当前的GUI元素的可用状态压入一个栈中,然后设置新的可用状态。GUIHelper.PopGUIEnabled方法则会从栈中弹出之前保存的GUI元素的可用状态,并恢复它。这样就可以在一段代码中临时禁用或启用一些GUI元素,而不影响其他代码中的GUI元素。
GUIHelper.PushGUIEnabled(toggle); //根据复选框的状态设置按钮的可用状态
if (GUILayout.Button("Click Me")) //绘制按钮会受到是否可选的影响
{
Debug.Log("You clicked the button!"); //打印日志
}
GUIHelper.PopGUIEnabled(); //恢复之前的可用状态

补充

可以通过UnityToolbarExtender来打开目标窗口,使用起来也非常简单

static ToolbarGUIUtility()  
{  
    uxToolPrefabOpen = EditorPrefs.GetBool("UXToolPrefabOpen", false);  
    uxToolPowerOpen = EditorPrefs.GetBool("UXToolPowerOpen", false);  
    ToolbarExtender.LeftToolbarGUI.Add(OnLeftToolbarGUI);  
    ToolbarExtender.RightToolbarGUI.Add(OnRightToolbarGUI);  
}
private static GUIStyle ToolbarButtonLeftStyle  
{  
    get  
    {  
        if (toolbarButtonLeftStyle == null) toolbarButtonLeftStyle = new GUIStyle("toolbarbuttonLeft");  
        return toolbarButtonLeftStyle;  
    }}
static void OnLeftToolbarGUI()  
{  
    if (TestCommon.TestHelper.ColorButton(new GUIContent("XXX配置", "XXXToolTip"), new Color(0.55f, 0.37f, 1f), GUILayoutOptions.Width(90), ToolbarButtonLeftStyle))  
    {        TestWindow.OpenWindow();  
    }

快速创建Button的管理者类

#if UNITY_EDITOR  
using System;  
using System.Collections.Generic;  
using System.Reflection;  
using Sirenix.Utilities;  
using Sirenix.Utilities.Editor;  
using UnityEditor;  
using UnityEngine;  
  
namespace TestCommon
{  
    public static class TestHelper
    {  
        private static GUIStyle ColoredButtonStyle = new GUIStyle(GUI.skin.button);  
  
        public static bool ColorButton(string text, Color color, int width, int height, GUIStyle guiStyle = null, GUIStyle labelGUIStyle = null)  
        {            ColoredButtonStyle.normal.textColor = Color.white;  
            GUIHelper.PushColor(color);  
            Rect buttonRect = GUILayoutUtility.GetRect(width, height);  
            bool res = guiStyle != null ? GUI.Button(buttonRect, "", guiStyle) : GUI.Button(buttonRect, "");  
            GUIHelper.PopColor();  
            GUI.Label(buttonRect, text, labelGUIStyle ?? SirenixGUIStyles.LabelCentered);  
            return res;  
        }  
        public static bool ColorButton(string text, Color color, GUILayoutOption[] guiLayoutOptions, GUIStyle guiStyle = null, GUIStyle labelGUIStyle = null)  
        {            ColoredButtonStyle.normal.textColor = Color.white;  
            GUIHelper.PushColor(color);  
            GUIHelper.PushContentColor(Color.clear);  
            bool res = guiStyle != null ? GUILayout.Button(text, guiStyle, guiLayoutOptions) : GUILayout.Button(text, guiLayoutOptions);  
            GUIHelper.PopContentColor();  
            GUIHelper.PopColor();  
            Rect buttonRect = GUILayoutUtility.GetLastRect();  
            GUI.Label(buttonRect, text, labelGUIStyle ?? SirenixGUIStyles.LabelCentered);  
            return res;  
        }  
        public static bool ColorButton(GUIContent guiContent, Color color, GUILayoutOption[] guiLayoutOptions, GUIStyle guiStyle = null, GUIStyle labelGUIStyle = null)  
        {            ColoredButtonStyle.normal.textColor = Color.white;  
            GUIHelper.PushColor(color);  
            GUIHelper.PushContentColor(Color.clear);  
            bool res = guiStyle != null ? GUILayout.Button(guiContent, guiStyle, guiLayoutOptions) : GUILayout.Button(guiContent, guiLayoutOptions);  
            GUIHelper.PopContentColor();  
            GUIHelper.PopColor();  
            Rect buttonRect = GUILayoutUtility.GetLastRect();  
            GUI.Label(buttonRect, guiContent.text, labelGUIStyle ?? SirenixGUIStyles.LabelCentered);  
            return res;  
        }  
        public static bool ColorButton(Rect rect, string text, Color color, GUIStyle guiStyle = null, GUIStyle labelGUIStyle = null)  
        {            GUIHelper.PushColor(color);  
            bool res = guiStyle != null ? GUI.Button(rect, "", guiStyle) : GUI.Button(rect, "");  
            GUIHelper.PopColor();  
            GUI.Label(rect, text, labelGUIStyle ?? SirenixGUIStyles.LabelCentered);  
            return res;  
        }  
        public static bool ColorButton(Rect rect, Texture2D texture2D, Color color, GUIStyle guiStyle = null)  
        {            GUIHelper.PushColor(color);  
            bool res = guiStyle != null ? GUI.Button(rect, texture2D, guiStyle) : GUI.Button(rect, texture2D);  
            GUIHelper.PopColor();  
            return res;  
        }  
        public static void RichLabel(Rect rect, string text, Color color, int fontSize = 12, bool italic = false, bool bold = false, GUIStyle guiStyle = null)  
        {            string richText = text;  
            richText = $"<size={fontSize}><color=#{ColorUtility.ToHtmlStringRGB(color)}>{richText}</color></size>";  
            if (italic) richText = $"<i>{richText}</i>";  
            if (bold) richText = $"<b>{richText}</b>";  
            if (guiStyle != null)  
                GUI.Label(rect, richText, guiStyle);  
            else  
                GUI.Label(rect, richText);  
        }  
        public static void RichLabel(Rect rect, GUIContent guiContent, Color color, int fontSize = 12, bool italic = false, bool bold = false, GUIStyle guiStyle = null)  
        {            string richText = guiContent.text;  
            richText = $"<size={fontSize}><color=#{ColorUtility.ToHtmlStringRGB(color)}>{richText}</color></size>";  
            if (italic) richText = $"<i>{richText}</i>";  
            if (bold) richText = $"<b>{richText}</b>";  
            guiContent.text = richText;  
            if (guiStyle != null)  
                GUI.Label(rect, guiContent, guiStyle);  
            else  
                GUI.Label(rect, guiContent);  
        }  
        public static void RichLabel(string text, Color color, int fontSize = 12, bool italic = false, bool bold = false, GUIStyle guiStyle = null, GUILayoutOption[] guiLayoutOptions = null)  
        {            string richText = text;  
            richText = $"<size={fontSize}><color=#{ColorUtility.ToHtmlStringRGB(color)}>{richText}</color></size>";  
            if (italic) richText = $"<i>{richText}</i>";  
            if (bold) richText = $"<b>{richText}</b>";  
            if (guiStyle != null)  
            {                if (guiLayoutOptions != null)  
                    GUILayout.Label(richText, guiStyle, guiLayoutOptions);  
                else  
                    GUILayout.Label(richText, guiStyle);  
            }            else  
            {  
                if (guiLayoutOptions != null)  
                    GUILayout.Label(richText, guiLayoutOptions);  
                else  
                    GUILayout.Label(richText);  
            }        }  
        public static void RichLabel(GUIContent guiContent, Color color, int fontSize = 12, bool italic = false, bool bold = false, GUIStyle guiStyle = null, GUILayoutOption[] guiLayoutOptions = null)  
        {            string richText = guiContent.text;  
            richText = $"<size={fontSize}><color=#{ColorUtility.ToHtmlStringRGB(color)}>{richText}</color></size>";  
            if (italic) richText = $"<i>{richText}</i>";  
            if (bold) richText = $"<b>{richText}</b>";  
            guiContent.text = richText;  
            if (guiStyle != null)  
            {                if (guiLayoutOptions != null)  
                    GUILayout.Label(guiContent, guiStyle, guiLayoutOptions);  
                else  
                    GUILayout.Label(guiContent, guiStyle);  
            }            else  
            {  
                if (guiLayoutOptions != null)  
                    GUILayout.Label(guiContent, guiLayoutOptions);  
                else  
                    GUILayout.Label(guiContent);  
            }        }  
        public enum Alignment  
        {  
            UpperLeft,  
            UpperCenter,  
            UpperRight,  
            MiddleLeft,  
            MiddleCenter,  
            MiddleRight,  
            BottomLeft,  
            BottomCenter,  
            BottomRight,  
        }  
  
        public static bool IsUpper(this Alignment alignment)  
        {            return alignment == Alignment.UpperRight || alignment == Alignment.MiddleRight || alignment == Alignment.BottomRight;  
        }  
        public static bool IsMiddle(this Alignment alignment)  
        {            return alignment == Alignment.MiddleLeft || alignment == Alignment.MiddleCenter || alignment == Alignment.MiddleRight;  
        }  
        public static bool IsBottom(this Alignment alignment)  
        {            return alignment == Alignment.BottomLeft || alignment == Alignment.BottomCenter || alignment == Alignment.BottomRight;  
        }  
        public static bool IsLeft(this Alignment alignment)  
        {            return alignment == Alignment.UpperLeft || alignment == Alignment.MiddleLeft || alignment == Alignment.BottomLeft;  
        }  
        public static bool IsRight(this Alignment alignment)  
        {            return alignment == Alignment.UpperRight || alignment == Alignment.MiddleRight || alignment == Alignment.BottomRight;  
        }  
        public static bool IsCenter(this Alignment alignment)  
        {            return alignment == Alignment.UpperCenter || alignment == Alignment.MiddleCenter || alignment == Alignment.BottomCenter;  
        }  
        public static void DrawResponsiveLayout(int rowWidth, List<int> elementWidths, Action<int> drawActions, Alignment alignment)  
        {            int accumulatedWidth = 0;  
            GUILayout.BeginVertical(GUILayoutOptions.ExpandWidth(false).ExpandHeight(false));  
            {                if (alignment.IsMiddle() || alignment.IsBottom()) GUILayout.FlexibleSpace();  
                GUILayout.BeginHorizontal();  
                if (alignment.IsRight() || alignment.IsCenter()) GUILayout.FlexibleSpace();  
                for (int index = 0; index < elementWidths.Count; index++)  
                {                    int elementWidth = elementWidths[index] + 4;  
                    if (accumulatedWidth + elementWidth > rowWidth)  
                    {                        accumulatedWidth = 0;  
                        if (alignment.IsLeft() || alignment.IsCenter()) GUILayout.FlexibleSpace();  
                        GUILayout.EndHorizontal();  
                        GUILayout.BeginHorizontal();  
                        if (alignment.IsRight() || alignment.IsCenter()) GUILayout.FlexibleSpace();  
                    }  
                    accumulatedWidth += elementWidth;                    drawActions.Invoke(index);  
                }  
                if (alignment.IsLeft() || alignment.IsCenter()) GUILayout.FlexibleSpace();  
                GUILayout.EndHorizontal();  
                if (alignment.IsMiddle() || alignment.IsUpper()) GUILayout.FlexibleSpace();  
            }            GUILayout.EndVertical();  
        }  
        [InitializeOnLoad]  
        public class ScrollableTextArea  
        {  
            private delegate string ScrollableTextAreaInternalDelegate(  
                Rect position,  
                string text,  
                ref Vector2 scrollPosition,  
                GUIStyle style);  
  
            private static readonly ScrollableTextAreaInternalDelegate EditorGUI_ScrollableTextAreaInternal;  
  
            static ScrollableTextArea()  
            {                MethodInfo method = typeof(EditorGUI).GetMethod("ScrollableTextAreaInternal", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);  
                if (method == null)  
                    return;  
                EditorGUI_ScrollableTextAreaInternal = (ScrollableTextAreaInternalDelegate)Delegate.CreateDelegate(typeof(ScrollableTextAreaInternalDelegate), method);  
            }  
            public static string EditorGUITextArea(Rect rect, string text, ref Vector2 scrollPos, int minLines = 0, int maxLines = 10)  
            {                return EditorGUI_ScrollableTextAreaInternal(rect, text, ref scrollPos, EditorStyles.textArea);  
            }  
            public static string EditorGUILayoutTextArea(string text, ref Vector2 scrollPos, int minLines = 0, int maxLines = 10)  
            {                float height = 32f + (float)((Mathf.Clamp(Mathf.CeilToInt(EditorStyles.textArea.CalcHeight(GUIHelper.TempContent(text), GUIHelper.ContextWidth) / 13f), minLines, maxLines) - 1) * 13);  
                Rect controlRect = EditorGUILayout.GetControlRect(false, height);  
                return EditorGUI_ScrollableTextAreaInternal(controlRect, text, ref scrollPos, EditorStyles.textArea);  
            }        }  
        public static Rect BeginColorBox(string label, Color color, params GUILayoutOption[] options)  
        {            Rect rect = SirenixEditorGUI.BeginBox(options);  
            SirenixEditorGUI.DrawSolidRect(rect, color);  
            SirenixEditorGUI.DrawBorders(rect, 1, new Color(0.24f, 0.24f, 0.24f));  
            SirenixEditorGUI.BeginBoxHeader();  
            float fieldWidth = EditorGUIUtility.fieldWidth;  
            EditorGUIUtility.fieldWidth = 10f;  
            Rect controlRect = EditorGUILayout.GetControlRect(false);  
            EditorGUIUtility.fieldWidth = fieldWidth;  
            GUI.Label(controlRect, label);  
            SirenixEditorGUI.EndBoxHeader();  
            return rect;  
        }  
        public static void EndColorBox()  
        {            SirenixEditorGUI.EndBox();  
        }  
        public static Color Grey(float value)  
        {            return new Color(value, value, value);  
        }  
        public static Color WithGrey(this Color color, float value)  
        {            return new Color(color.r * value, color.g * value, color.b * value);  
        }  
        public static Color WithAlpha(this Color color, float alpha)  
        {            color.a = alpha;  
            return color;  
        }    }}  
#endif

参考

十分钟入门Unity革命性编辑器拓展插件——Odin_哔哩哔哩_bilibili
Odin常用功能整理 | 登峰造极者,殊途亦同归。 (lfzxb.top)
marijnz/unity-toolbar-extender at dbd76ed996483d219c39d240f785b1790aa039ed (github.com)文章来源地址https://www.toymoban.com/news/detail-720338.html

到了这里,关于Unity编辑器拓展-Odin的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity编辑器】拓展Hierarchy视图

    目录 1、拓展菜单 2、拓展布局 3、重写菜单 在Hierarchy视图中点击Create按钮,弹出的菜单My Create-Cube就是自定义拓展菜单 菜单中已经包含了系统默认的一些菜单项,我们拓展的原理就是重写MenuItem的自定义路径。Create按钮下的菜单项都在GameOject路径下面,所以只要开头是GameOb

    2024年02月02日
    浏览(49)
  • 【Unity编辑器】拓展Inspector视图

    目录 1、拓展源生组件 2、拓展继承组件 3、组件不可编辑 4、Context菜单 摄像机就是典型的源生组件。它的局限性就是拓展组件只能加在源生组件的最上面或者最下面,不能插在中间,不过这样也就够了 CustomEditor()表示自定义哪个组件,OnInspectorGUI()可以对它进行重新绘制,b

    2024年02月07日
    浏览(67)
  • Unity UGUI一键绑定UI控件工具(编辑器拓展)

    全为一键生成 实现自动生成代码绑定UI控件 并生成字典保存UI控件 减少自己拖拽 和手动书写过程 适用动态加载面板 建议搭配UI框架使用 根据当前选中的gameobject 查找其下方是否有对应类型的控件 有就保存到字典中 然后通过向上递归拼凑地址,然后生成到粘贴板 直接粘贴到目

    2024年04月23日
    浏览(61)
  • Unity编辑器拓展——Editor模式下屏幕坐标转换为世界坐标

    发会牢骚,最近一直在做Unity的编辑器拓展,其中难的地方不少,但不至于到看不懂的地步,可一做到关于坐标转换的内容时把我弄不会了。 这个不查不知道,一查吓一跳,Unity的坐标系非常多,有世界坐标,屏幕坐标,局部坐标,视窗坐标等等,而且每一个都是不一样的坐

    2024年02月03日
    浏览(50)
  • Unity读书系列《Unity3D游戏开发》——编辑器的结构

    本篇对应标题书籍的第二章编辑器的结构,也就是unity的编辑器的使用及菜单的使用。 当我们制作的软件或游戏需要多人合作时,就会使用git、svn进行版本管理。一般来说只保留Assets、ProjectSettings、Packages这几个文件夹,git会自动生成.git文件,我们添加需要屏蔽的文件夹或后

    2024年01月25日
    浏览(126)
  • 从零开始入门创作游戏——Unity编辑器的使用

    还没找到工作的我继续瞎折腾中,上次搭建环境就花了我3天的时间 从零开始入门创作游戏——Unity3d的环境搭建_默哀d的博客-CSDN博客 接下来是根据油土鳖的视频学习创作的一个小恐龙跳跳跳游戏,直接上手做一次学得更多 https://www.youtube.com/watch?v=UdM9DEys-rI 选择2D核心模板就可

    2024年02月05日
    浏览(65)
  • Unity功能——编辑器模式下隐藏/显示游戏对象的快捷方法

    声明:本文为个人笔记,用于学习研究使用非商用,内容为个人研究及综合整理所得,若有违规,请联系,违规必改。 unity20XX.X.X VS20XX 在编辑器模式下,想快捷的显示/隐藏一个游戏对象. 实现原理: 对组件进行扩展方法.对MonoBehaviour ,Transform,GameObject 组件进行扩展方法 快捷键为

    2024年02月08日
    浏览(59)
  • Unity3d C#利用Editor编辑器拓展实现配置UI背景样式一键设置UI背景样式功能(含源码)

    在开发UI滚动列表的时候,经常会有每项的背景图不统一的情况,会间隔重复的情况居多。这种情况下,手动去设置间隔一行的背景图或者颜色是比较麻烦的。在此背景下,笔者尝试写个小工具,在搭建UI时配置一下循环背景的样式,可以通过一键点击后设置UI背景的样式,省

    2024年02月03日
    浏览(52)
  • 用odin实现的资源复制编辑器

    用odin实现了一个资源复制编辑器,使用要安装odin,功能是把要复制的资源路径一个个添加设置,点copy能把列表里的资源全部复制,支持目录复制到目录,文件复制到目录,文件复制替换。提升效率,让自己有更多的时间研究其他东西或者休息,需要注意的是只有一个目标路

    2024年04月16日
    浏览(54)
  • Unity编辑器扩展 | 编辑器扩展基础入门

    前言 当谈到游戏开发工具,Unity编辑器是一个备受赞誉的平台。它为开发者提供了一个强大且灵活的环境,使他们能够创建令人惊叹的游戏和交互式体验。 然而,Unity编辑器本身也是可以扩展和定制的,这为开发者提供了进一步提升工作流程和增强功能的机会。 在Unity 编辑器

    2024年02月10日
    浏览(77)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包