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

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

系列文章目录

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


一.开发环境

以下为本人测试时环境:
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.命名空间

using Sirenix.OdinInspector;

2.AssetsOnly\SceneObjectsOnly:引用限制为预制体\场景物体

限制拖拽赋值的物体来源

[Title("Assets only")]
    [AssetsOnly]
    public List<GameObject> OnlyPrefabs;

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

3.Delayer:延迟赋值

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

  [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:信息提示–标题/内容

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

[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

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

 [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:改变颜色

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

[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:按钮组

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

[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:隐藏标签

类似隐藏变量名

[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:改变属性显示顺序

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

 [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面板上类似行间距

 // 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:只读

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

[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:必须

面板上必须赋值否则报错

[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面板上搜索

[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面板上

 [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:标题用于在属性上方制作粗体标题

可用于方法属性字段

 [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面板设置显示对应的子类属性

// 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 属性。

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.AssetsOnly\SceneObjectsOnly:引用限制为预制体\场景物体

限制拖拽赋值的物体来源

[Title("Assets only")]
    [AssetsOnly]
    public List<GameObject> OnlyPrefabs;

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

19.ValidateInput:输入验证

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

[ValidateInput("CheckSex", "", InfoMessageType.Error)]
    public string sex;
    public bool CheckSex(string sex, ref string errorMessage, ref InfoMessageType? messageType)
    {
        errorMessage = "性别输入错误";
        return sex == "男";
    }  

输入错误值:
在这里插入图片描述

输入正确值:

在这里插入图片描述

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

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

 [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

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ۓ明哲ڪ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值