Unity插件——Odin使用心得(一)「建议收藏」

2022-09-13 17:49:51 浏览数 (1)

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

声明:本文为个人笔记,用于个人学习研究使用非商用,内容为个人研究及综合整理所得,若有违规,请联系,违规必改

系列文章目录

Unity插件——Odin使用心得(一)

Unity插件——Odin使用心得(一)

  • 系列文章目录
  • 一.开发环境
  • 二.使用前准备
  • 三 .常用功能讲解
    • 1.命名空间
    • 2.AssetsOnlySceneObjectsOnly:引用限制为预制体场景物体
    • 3.Delayer:延迟赋值
    • 4.DetailedInfoBox:信息提示–标题/内容
    • 5.EnableGUI:激活GUI
    • 6.GUIColor:改变颜色
    • 7.ButtonGroup:按钮组
    • 8.HideLabel:隐藏标签
    • 9.PropertyOrder:改变属性显示顺序
    • 10.PropertySpace:属性空间/属性间隔
    • 11.ReadOnly:只读
    • 12.Required:必须
    • 13.Searchable:可搜索
    • 14.ShowInInspector:属性显示在Inspector面板
    • 15.Title:标题用于在属性上方制作粗体标题
    • 16.TypeFilter: 对基础过滤,显示需要(子类)的属性
    • 17.TypeInfoBox:类型信息框属性
    • 18.AssetsOnlySceneObjectsOnly:引用限制为预制体场景物体
    • 19.ValidateInput:输入验证
    • 20.ValueDropdown 用于任何属性,并创建一个带有可配置选项的下拉列表。
  • 四.总结
  • 五:相关链接

一.开发环境

以下为本人测试时环境: VS版本: 2019 Odin版本:3.0.9 Unity版本:2019.3.6

二.使用前准备

1.导入插件:Unity–Asset Store–Odin–导入 2.Tools–Getting Started–Open Attributes Overview –Essentials 本文对应Essentials章节内容为基础常见功能 3.如下图所示:

备注:本文实例代码多来自于官方Demo示例,文末附官方手册地址.本文内容为本人总结时记录,除各特性代码实例及对应配图外多个特性名下方配有本人使用时感悟,可类比参考.本文仅对应官方手册Essentials部分,后续待更新.

三 .常用功能讲解

1.命名空间

代码语言:javascript复制
using Sirenix.OdinInspector;

2.AssetsOnlySceneObjectsOnly:引用限制为预制体场景物体

限制拖拽赋值的物体来源

代码语言:javascript复制
[Title("Assets only")]
    [AssetsOnly]
    public List<GameObject> OnlyPrefabs;

[Title("Scene Objects only")]
    [SceneObjectsOnly]
    public List<GameObject> OnlySceneObjects;

3.Delayer:延迟赋值

当脱离焦点(当前选中/选中)后赋值

代码语言:javascript复制
  [Delayed]
    [OnValueChanged("OnValueChanged")]//当值改变时触发的事件
    public int DelayedField;
    
    // ... but the DelayedProperty can, as the name suggests, also be applied to properties.
    [ShowInInspector, DelayedProperty]
    [OnValueChanged("OnValueChanged")]
    public string DelayedProperty { 
    get; set; }
    
    private void OnValueChanged()
    { 
   
        Debug.Log("Value changed!");
    }

4.DetailedInfoBox:信息提示–标题/内容

默认显示标题文字,点击后显示内容文字

代码语言:javascript复制
[DetailedInfoBox("Click the DetailedInfoBox...", "... to reveal more information!n"   "This allows you to reduce unnecessary clutter in your editors, and still have all the relavant information available when required.")]
    public int Field;

   [DetailedInfoBox("标题","内容",InfoMessageType.None)]
    public int TestDetailed;

5.EnableGUI:激活GUI

允许复制,否则仅显示灰色不可复制

代码语言:javascript复制
 [ShowInInspector]
    public int DisableProp1 { 
    get; }  
  
    [ShowInInspector,EnableGUI]
    public int DisableProp2 { 
    get;} 
   
    [ShowInInspector, EnableGUI]
    public int DisableProp3 { 
    get; set; }

此图参考: https://zhuanlan.zhihu.com/p/408002569

6.GUIColor:改变颜色

改变字段属性颜色 方便分类或提示

代码语言:javascript复制
[GUIColor(0.3f, 0.8f, 0.8f, 1f)]
    public int ColoredInt1;
[GUIColor("GetButtonColor")]//自动变化颜色
  private static void IAmFabulous()
    { 
   
    }
#if UNITY_EDITOR // Editor-related code must be excluded from builds
    private static Color GetButtonColor()
    { 
   
        Sirenix.Utilities.Editor.GUIHelper.RequestRepaint();
        return Color.HSVToRGB(Mathf.Cos((float)UnityEditor.EditorApplication.timeSinceStartup   1f) * 0.225f   0.325f, 1, 1);
    }
#endif

7.ButtonGroup:按钮组

将多个按钮水平放置在一组中

代码语言:javascript复制
[ButtonGroup]
    [GUIColor(1, 0.6f, 0.4f)]
    private void Cancel()
    { 
   
    }


    [ButtonGroup]
    [GUIColor(1, 0.6f, 0.4f)]
    private void Cancel1()
    { 
   
    }


    [ButtonGroup]
    [GUIColor(1, 0.6f, 0.4f)]
    private void Cancel2()
    { 
   
    }


    [ButtonGroup]
    [GUIColor(1, 0.6f, 0.4f)]
    private void Cancel3()
    { 
   
    }

8.HideLabel:隐藏标签

类似隐藏变量名

代码语言:javascript复制
[Title("Wide Colors")]
    [HideLabel]
    [ColorPalette("Fall")]
    public Color WideColor1;
    
    [HideLabel]
    [ColorPalette("Fall")]
    public Color WideColor2;
    
    [Title("Wide Vector")]
    [HideLabel]
    public Vector3 WideVector1;
    
    [HideLabel]
    public Vector4 WideVector2;

    [Title("Wide String")]
    [HideLabel]
    public string WideString;//单行 仅一行输入显示
    
    [Title("Wide Multiline Text Field")]
    [HideLabel]
    [MultiLineProperty]//字符串可多行显示
    public string WideMultilineTextField = "";

9.PropertyOrder:改变属性显示顺序

如下:类似定义属性时的顺序变化

代码语言:javascript复制
 [PropertyOrder(1)]//值大最后显示
    public int Second;
    
    [InfoBox("PropertyOrder is used to change the order of properties in the inspector.")]
    [PropertyOrder(-1)]//值小优先显示
    public int First;


    public int a;//a比b先定义显示在上面
    public int b;


    public int d;//d比c先定义显示在上面
    public int c;

10.PropertySpace:属性空间/属性间隔

类似Unity自带的Space但可用于属性,在Inspace面板上类似行间距

代码语言:javascript复制
 // PropertySpace and Space attributes are virtually identical...
    [Space]//仅用于字段
    public int Space;
    
    // ... but the PropertySpace can, as the name suggests, also be applied to properties.
    [ShowInInspector, PropertySpace]//可用于属性
    public string Property { 
    get; set; }
    
    // You can also control spacing both before and after the PropertySpace attribute.
    [PropertySpace(SpaceBefore = 0, SpaceAfter = 60), PropertyOrder(2)]
    public int BeforeAndAfter;

11.ReadOnly:只读

只用了显示,不可修改及复制,便于运行时检测数值调试等(好像只能用于字段对属性无效)

代码语言:javascript复制
[ReadOnly]
    public string MyString = "This is displayed as text";
    
    [ReadOnly]
    public int MyInt = 9001;
    
    [ReadOnly]
    public int[] MyIntList = new int[] { 
    1, 2, 3, 4, 5, 6, 7, };

12.Required:必须

面板上必须赋值否则报错

代码语言:javascript复制
[Required]
public GameObject MyGameObject;

[Required("Custom error message.")]
public Rigidbody MyRigidbody;

[InfoBox("Use $ to indicate a member string as message.")]
[Required("$DynamicMessage")]
public GameObject GameObject;

public string DynamicMessage = "Dynamic error message";

13.Searchable:可搜索

可通过对应关键字搜索可 参考Unity Hierarchy面板上搜索

代码语言:javascript复制
[Searchable]
public List<Perk> Perks = new List<Perk>()
{ 
   
    new Perk()
    { 
   
        Name = "Old Sage",
        Effects = new List<Effect>()
        { 
   
            new Effect() { 
    Skill = Skill.Wisdom, Value = 2, },
            new Effect() { 
    Skill = Skill.Intelligence, Value = 1, },
            new Effect() { 
    Skill = Skill.Strength, Value = -2 },
        },
    },
    new Perk()
    { 
   
        Name = "Hardened Criminal",
        Effects = new List<Effect>()
        { 
   
            new Effect() { 
    Skill = Skill.Dexterity, Value = 2, },
            new Effect() { 
    Skill = Skill.Strength, Value = 1, },
            new Effect() { 
    Skill = Skill.Charisma, Value = -2 },
        },
    },
    new Perk()
    { 
   
        Name = "Born Leader",
        Effects = new List<Effect>()
        { 
   
            new Effect() { 
    Skill = Skill.Charisma, Value = 2, },
            new Effect() { 
    Skill = Skill.Intelligence, Value = -3 },
        },
    },
    new Perk()
    { 
   
        Name = "Village Idiot",
        Effects = new List<Effect>()
        { 
   
            new Effect() { 
    Skill = Skill.Charisma, Value = 4, },
            new Effect() { 
    Skill = Skill.Constitution, Value = 2, },
            new Effect() { 
    Skill = Skill.Intelligence, Value = -3 },
            new Effect() { 
    Skill = Skill.Wisdom, Value = -3 },
        },
    },
};
[Serializable]
public class Perk
{ 
   
    public string Name;
    [TableList]
    public List<Effect> Effects;
}
[Serializable]
public class Effect
{ 
   
    public Skill Skill;
    public float Value;
}
public enum Skill
{ 
   
    Strength,
    Dexterity,
    Constitution,
    Intelligence,
    Wisdom,
    Charisma,
}

搜索前:

搜索后

14.ShowInInspector:属性显示在Inspector面板

可将(包括静态的)属性显示在Inspector面板上

代码语言:javascript复制
 [ShowInInspector]
    private int myPrivateInt;
    
    [ShowInInspector]
    public int MyPropertyInt { 
    get; set; }
    
    [ShowInInspector]
    public int ReadOnlyProperty
    { 
   
        get { 
    return this.myPrivateInt; }
    }
    
    [ShowInInspector]
    public static bool StaticProperty { 
    get; set; }
    [ShowInInspector]
    public static string StaticStringProperty { 
    get; set; }

15.Title:标题用于在属性上方制作粗体标题

可用于方法属性字段

代码语言:javascript复制
 [Title("Titles and Headers")]
    public string MyTitle = "My Dynamic Title";
    public string MySubtitle = "My Dynamic Subtitle";
    
    [Title("Static title")]
    public int C;
    public int D;
    
    [Title("Static title", "Static subtitle")]
    public int E;
    public int F;

16.TypeFilter: 对基础过滤,显示需要(子类)的属性

例如:基类为BaseClass 可以在Inspace面板设置显示对应的子类属性

代码语言:javascript复制
// TypeFilterExamplesComponent.cs
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;


public class TypeFilterExamplesComponent : SerializedMonoBehaviour
{ 
   
    [TypeFilter("GetFilteredTypeList")]
    public BaseClass A, B;
    
    [TypeFilter("GetFilteredTypeList")]
    public BaseClass[] Array = new BaseClass[3];
    
    public IEnumerable<Type> GetFilteredTypeList()
    { 
   
        var q = typeof(BaseClass).Assembly.GetTypes()
            .Where(x => !x.IsAbstract)                                          // Excludes BaseClass
            .Where(x => !x.IsGenericTypeDefinition)                             // Excludes C1<>
            .Where(x => typeof(BaseClass).IsAssignableFrom(x));                 // Excludes classes not inheriting from BaseClass
    
        // Adds various C1<T> type variants.
        q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(GameObject)));
        q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(AnimationCurve)));
        q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(List<float>)));
    
        return q;
    }
    
    public abstract class BaseClass
    { 
   
        public int BaseField;
    }
    
    public class A1 : BaseClass { 
    public int _A1; }
    public class A2 : A1 { 
    public int _A2; }
    public class A3 : A2 { 
    public int _A3; }
    public class B1 : BaseClass { 
    public int _B1; }
    public class B2 : B1 { 
    public int _B2; }
    public class B3 : B2 { 
    public int _B3; }
    public class C1<T> : BaseClass { 
    public T C; }
}

17.TypeInfoBox:类型信息框属性

属性将一个信息框添加到检查器中类型的最顶部。使用它可以将信息框添加到检查器中类的顶部,而不必使用 PropertyOrder 和 OnInspectorGUI 属性。

代码语言:javascript复制
public MyType MyObject = new MyType();
[InfoBox("Click the pen icon to open a new inspector for the Scripty object.")]
[InlineEditor]
public MyScriptyScriptableObject Scripty;
[Serializable]
[TypeInfoBox("The TypeInfoBox attribute can be put on type definitions and will result in an InfoBox being drawn at the top of a property.")]
public class MyType
{ 
   
    public int Value;
}
//[TypeInfoBox("The TypeInfoBox attribute can also be used to display a text at the top of, for example, MonoBehaviours or ScriptableObjects.")]
//public class MyScriptyScriptableObject : ScriptableObject
//{ 
   
// public string MyText = ExampleHelper.GetString();
// [TextArea(10, 15)]
// public string Box;
//}
[OnInspectorInit]
private void CreateData()
{ 
   
    Scripty = ExampleHelper.GetScriptableObject<MyScriptyScriptableObject>("Scripty");
}
[OnInspectorDispose]
private void CleanupData()
{ 
   
    if (Scripty != null) UnityEngine.Object.DestroyImmediate(Scripty);
}

18.AssetsOnlySceneObjectsOnly:引用限制为预制体场景物体

限制拖拽赋值的物体来源

代码语言:javascript复制
[Title("Assets only")]
    [AssetsOnly]
    public List<GameObject> OnlyPrefabs;

[Title("Scene Objects only")]
    [SceneObjectsOnly]
    public List<GameObject> OnlySceneObjects;

19.ValidateInput:输入验证

用于任何属性,并允许验证来自 inspector面板的输入。使用它来强制执行正确的值。

代码语言:javascript复制
[ValidateInput("CheckSex", "", InfoMessageType.Error)]
    public string sex;
    public bool CheckSex(string sex, ref string errorMessage, ref InfoMessageType? messageType)
    { 
   
        errorMessage = "性别输入错误";
        return sex == "男";
    }  

输入错误值:

输入正确值:

20.ValueDropdown 用于任何属性,并创建一个带有可配置选项的下拉列表。

使用它为用户提供一组特定的选项以供选择。(带枚举器类型产生类似枚举的下拉框)

代码语言:javascript复制
 [ValueDropdown("TextureSizes")]
    public int SomeSize1;
    
    [ValueDropdown("FriendlyTextureSizes")]
    public int SomeSize2;
    
    [ValueDropdown("FriendlyTextureSizes", AppendNextDrawer = true, DisableGUIInAppendedDrawer = true)]
    public int SomeSize3;
    
    [ValueDropdown("GetListOfMonoBehaviours", AppendNextDrawer = true)]
    public MonoBehaviour SomeMonoBehaviour;
    
    [ValueDropdown("KeyCodes")]
    public KeyCode FilteredEnum;
    
    [ValueDropdown("TreeViewOfInts", ExpandAllMenuItems = true)]
    public List<int> IntTreview = new List<int>() { 
    1, 2, 7 };
    
    [ValueDropdown("GetAllSceneObjects", IsUniqueList = true)]
    public List<GameObject> UniqueGameobjectList;
    
    [ValueDropdown("GetAllSceneObjects", IsUniqueList = true, DropdownTitle = "Select Scene Object", DrawDropdownForListElements = false, ExcludeExistingValuesInList = true)]
    public List<GameObject> UniqueGameobjectListMode2;
    
#if UNITY_EDITOR // Editor-related code must be excluded from builds
#pragma warning disable // And these members are in fact being used, though the compiler cannot tell. Let's not have bothersome warnings.
    private IEnumerable TreeViewOfInts = new ValueDropdownList<int>()
    { 
   
        { 
    "Node 1/Node 1.1", 1 },
        { 
    "Node 1/Node 1.2", 2 },
        { 
    "Node 2/Node 2.1", 3 },
        { 
    "Node 3/Node 3.1", 4 },
        { 
    "Node 3/Node 3.2", 5 },
        { 
    "Node 1/Node 3.1/Node 3.1.1", 6 },
        { 
    "Node 1/Node 3.1/Node 3.1.2", 7 },
    };
    
    private IEnumerable<MonoBehaviour> GetListOfMonoBehaviours()
    { 
   
        return GameObject.FindObjectsOfType<MonoBehaviour>();
    }
    
    private static IEnumerable<KeyCode> KeyCodes = Enumerable.Range((int)KeyCode.Alpha0, 10).Cast<KeyCode>();
    
    private static IEnumerable GetAllSceneObjects()
    { 
   
        Func<Transform, string> getPath = null;
        getPath = x => (x ? getPath(x.parent)   "/"   x.gameObject.name : "");
        return GameObject.FindObjectsOfType<GameObject>().Select(x => new ValueDropdownItem(getPath(x.transform), x));
    }
    
    private static IEnumerable GetAllScriptableObjects()
    { 
   
        return UnityEditor.AssetDatabase.FindAssets("t:ScriptableObject")
            .Select(x => UnityEditor.AssetDatabase.GUIDToAssetPath(x))
            .Select(x => new ValueDropdownItem(x, UnityEditor.AssetDatabase.LoadAssetAtPath<ScriptableObject>(x)));
    }
    
    private static IEnumerable GetAllSirenixAssets()
    { 
   
        var root = "Assets/Plugins/Sirenix/";
    
        return UnityEditor.AssetDatabase.GetAllAssetPaths()
            .Where(x => x.StartsWith(root))
            .Select(x => x.Substring(root.Length))
            .Select(x => new ValueDropdownItem(x, UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(root   x)));
    }
    
    private static IEnumerable FriendlyTextureSizes = new ValueDropdownList<int>()
    { 
   
        { 
    "Small", 256 },
        { 
    "Medium", 512 },
        { 
    "Large", 1024 },
    };
    
    private static int[] TextureSizes = new int[] { 
    256, 512, 1024 };
#endif

四.总结

本文为作者对Odin插件的使用总结,因整个插件内容较多,篇幅过长,参考官方实例结构,该章节仅描述了Essentials部分,后续更新后会在本文开头及文章末尾附上链接.,学习建议以官方文档为主.

五:相关链接

Odin官方手册地址: https://odininspector.com/attributes/value-dropdown-attribute

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/162839.html原文链接:https://javaforall.cn

0 人点赞