-
-
Notifications
You must be signed in to change notification settings - Fork 245
Attributes
AutoProperty — Assign fields automatically
ButtonMethod — Display button in inspector
CharactersRange — Filter string field by the set of characters
ConditionalField — Conditionally display property in inspector, based on some other property value
ConstantsSelection — Popup of const, readonly or static fields and properties
DefinedValues — Display Dropdown with predefined values
DisplayInspector — Display one inspector inside of another
Foldout — Group your fields in inspector
InitializationField — Field that is not editable in playmode
Tag, Layer, SpriteLayer — Dropdown with Tags, Layers or SpriteLayers
MinMaxRange, RangedFloat and RangedInt — Ranged sliders
RangeVector — Limit Vector values set in inspector to a specified range
MaxValue, MinValue and PositiveValueOnly — Validation for numbers and vectors
MustBeAssigned — Automatically checks if field is assigned
OverrideLabel — Change visible in Inspector field name
ReadOnly — Draw property with disabled GUI
RegexString — Filter string field by the Regular Expression
RequireTag and RequireLayer — Automatically set Tag and Layer
Scene — Friendly way to keep Scene name as a string. See also SceneReference type
SearchableEnum — Nice UI for enums with lots of elements
Separator — Draw separator with or without title
Note, that in most of the cases attribute stacking is not supported yet.
You may try to mix several attributes on the same field and check if it's working, but further work is required to fully support this feature.
Automatically assign property on Scene Save event (works best with AutoSave Feature!)
When used in Prefabs will be checked on Prefab Stage Opened and Saved
It can be used with ScriptableObjects, but you need to enable this feature in Settings.
Bind and cache components and arrays of components.
Allows to save some code time and gain bits of performance with absence of GetComponent calls
You'll get error message if there is no matching components.
Several modes are supported:
- AutoPropertyMode.Children is default, similar to GetComponentsInChildren()
- AutoPropertyMode.Parent — similar to GetComponentsInParent()
- AutoPropertyMode.Scene — similar to Object.FindObjectsOfType()
- AutoPropertyMode.Asset will search for this asset type in Assets folder (won't work if disabled in settings)
- AutoPropertyMode.Any works as "Scene + Asset" modes
[AutoProperty(AutoPropertyMode.Parent)] public Rigidbody AbsentRB;
// Assuming AudioManager is "ScriptableObject Singleton" in your project
[AutoProperty(AutoPropertyMode.Asset)] public AudioManager AudioManager;
[AutoProperty] public Collider[] ChildColliders;
[AutoProperty] public GuidComponent[] ChildGuids;
You can disable the error message by specifying allowEmpty
parameter
Another use-case for this attribute:
// Automatically updated collection of types on the scene, how cool is that 😁?
[AutoProperty(AutoPropertyMode.Scene)] public Camera[] AllCamerasOnScene;
You can use the predicate method to filter out the lookup.
Pass the name of the method as the second parameter and the type of the class with the method as a third:
[AutoProperty(AutoPropertyMode.Asset, nameof(EventPredicate), typeof(TestScript))]
public EventSO[] Events; // There are EventA, EventB, EventC in the project, only EventA and EventC are assigned.
public static bool EventPredicate(UnityEngine.Object obj) => obj.name != "EventB";
You may apply this attribute to any method and it will appear in inspector as a button.
If this method returns anything, the result will be logged to the console.
By default the button drawn in the bottom of the inspector, but you can change this with the first parameter.
public Collider[] Colliders;
[ButtonMethod]
private string CollectColliders()
{
Colliders = FindObjectsOfType<Collider>();
return Colliders.Length + " Colliders found on scene, cached";
}
It is possible to draw the button conditionally. Check ConditionalField examples. The only difference is the additional first "DrawOrder" parameter:
[MustBeAssigned] public Transform ChildTransform;
// Button shown when ChildTransform is null
[ButtonMethod(ButtonMethodDrawOrder.BeforeInspector, nameof(TargetStack), true), UsedImplicitly]
private void CreateChild()
{
var choldGO = new GameObject(name + " Child Object");
choldGO.transform.SetParent(transform);
choldGO.transform.localPosition = Vector3.zero;
ChildTransform = choldGO.transform;
}
See also RegexString Attribute
Allows to restrict the string field by the set of characters
Optionally, you can use several Modes:
// By default, only characters in range will be allowed
CharactersRangeMode.Allow
// Characters in range will be removed from the string
CharactersRangeMode.Disallow
// Highlight the field if any of the specified characters were fould
CharactersRangeMode.WarningIfAny
// Highlight the field if some characters in string are not the characters from specified range
CharactersRangeMode.WarningIfNotMatch
Also with the third parameter you can disable "Ignore Case" option
[CharactersRange("0123456789.-")]
public string DigitsOnly;
[CharactersRange("1234567890ABCDEF", CharacterRangeMode.WarningIfNotMatch)]
public string HexValue;
Thanks to tonygiang for this Attribute 🤓!
This attribute allows you to conditionally hide/show fields in inspector, based on some other field.
You may also use ReadOnlyAttribute to make field disabled instead of hiding it
By default ConditionalField checks if "fieldToCheck" value is not null, not 0 and not empty.
Basically it means "if something assigned to field A, show field B".
Second parameter is "inverse", well.. to inverse the result 🙂 This one is optional
You may also specify "compareValues". Very handy to check for specific enum value for example!
[Separator("GameObject / Component")]
public Transform Target;
[ConditionalField(nameof(Target))] public float TargetSpeed;
[ConditionalField(nameof(Target), inverse:true)] public float Speed;
[Separator("Bool")]
public bool Teleport;
[ConditionalField(nameof(Teleport))] public float TeleportationDelay;
[Separator("String")]
public string Hello;
[ConditionalField(nameof(Hello), false, "Hello")] public string HelloWorld = "World! :)";
[ConditionalField(nameof(Hello))] public string HelloHint = "Print \"Hello\"!";
[Separator("Enum")]
public AIState State = AIState.None;
[ConditionalField(nameof(State), false, AIState.Walk)] public float WalkSpeed;
[ConditionalField(nameof(State), false, AIState.Idle)] public float IdleTime;
Thanks to Kaynn-Cahya you may also specify several compare values!🤓:
public AIState State = AIState.None;
[ConditionalField(nameof(State), false, AIState.Walk, AIState.Run)] public float Speed;
Alternatively, instead of using the values of other fields as conditions, you may use the predicate method for more complex scenarios:
public int Value;
[ConditionalField(true, nameof(Predicate))] public string ValueIsEven;
private bool Predicate() => Value % 2 == 0;
// Example with inverse
public int Age;
[ConditionalField(true, nameof(IsChild))]
public bool HomeworkIsDone;
[ConditionalField(true, nameof(IsChild), true)]
public bool JobTaskIsDone;
There is a natural limitation in Unity preventing usage of attribute drawers (such as ConditionalField) on arrays.
To handle such cases CollectionWrapper was made.
public bool ShowWrappedCollection;
[ConditionalField(nameof(ShowWrappedCollection))]
public GOCollection WrappedCollection;
[Serializable]
public class GOCollection : CollectionWrapper<GameObject> {}
Since Unity 2020.1 you may use generics directly but field name won't be shown in inspector 🙄
[ConditionalField(nameof(ShowWrappedCollection))]
public CollectionWrapper<GameObject> WrappedCollection;
As it is not supported at the moment to use several ConditionalField attributes on the same field, you can utilize this overloads, to specify several conditions:
public enum Test {C, D, E}
public bool A;
public bool B;
public Test T;
[ConditionalField(nameof(A))] public string IsA;
[ConditionalField(nameof(B), true)] public string NotB;
[ConditionalField(nameof(A), nameof(B))] public string AandB;
[ConditionalField(new []{nameof(A), nameof(B)}, new []{true})] public string NotAandB;
[ConditionalField(new []{nameof(A), nameof(B)}, new []{false, true})] public string AnotB;
[ConditionalField(new []{nameof(A), nameof(B)}, new []{true, true})] public string NotAandNotB;
[ConditionalField(new[] { nameof(T), nameof(A), nameof(B) }, new[] { false, true, true }, Test.C )] public string NotAandNotBButC;
Allows to display a popup of const, readonly, static fields and properties defined in specified script:
[ConstantsSelection(typeof(PresetLayers))] public string DefaultLayer = "Default";
[ConstantsSelection(typeof(Vector3))] public Vector3 UnityDefaultVectors;
[ConstantsSelection(typeof(Color))] public Color UnityDefaultColors;
public class PresetLayers
{
public const string Interactive = "Interactive";
public const string Obstacle = "Obstacle";
}
This attribute allows to display the dropdown of predefined values.
You can just pass a bunch of predefined values:
[DefinedValues("Hello", "World")]
public string IsItHelloOrWorld;
[DefinedValues(.5f, 1f, 1.5f, 2f)]
public float SimpleFloatDropdown;
You can show custom text instead of actual values in the dropdown.
To do so, as the first parameter ("withLabels") you should specify "true" and pass a string after every value:
[DefinedValues(true,
-1, "Left", 0, "Undefined", 1, "Right")]
public int DefaultLookDirection;
But the most interesting part is the ability to use the method that will return an array of predefined values!
[DefinedValues(nameof(StringTest))] public string StringSelection;
[DefinedValues(nameof(TransformTest))] public Transform ChildReference;
private string[] StringTest() => new[] { "A", "B", "C" };
private Transform[] TransformTest()
{
var childs = transform.GetChilds();
childs.Insert(0, null);
return childs.ToArray();
}
Displays one inspector inside of another. It's handy if you'd like to store some settings in scriptable objects.
[DisplayInspector(displayScriptField:false)] to hide object field once assigned (useful for "single instance" settings)
[CreateAssetMenu]
public class AgentAIContextSettings : ScriptableObject
{
public bool WanderAround;
public float WanderDistance = 5;
}
[DisplayInspector]
public AgentAIContextSettings Settings;
Set displayScriptField to false (by default it's true) to hide property field once
[DisplayInspector(displayScriptField:false)]
Group the fields in the inspector.
Optionally, add "true" as a second parameter to group further fields in the same foldout:
public class Player : MonoBehaviour
{
[Foldout("Health Settings", true)]
public int HP;
public int Defence;
[Foldout("Attack Settings")]
public int Damage;
[Foldout("Attack Settings")]
public int Piercing;
[Foldout("Attack Settings")]
public float CriticalMultiplier;
public string DisplayName;
}
Note, that Foldout need to be part of MonoBehaviour or ScriptableObject, it is not intended to work in Serializable classes
Thanks to PixeyeHQ for this attribute! 🤓 Official repo
Field will be not editable at playmode:
[InitializationField] public int MaxHP;
[ReadOnly] public int CurrentHP;
69 in this example is pure random, I swear!
[Tag]
public string Tag;
[Layer]
public int Layer;
[SpriteLayerAttribute]
public int SortingLayer;
by Richard Fine
public class RandomisedHealth : MonoBehaviour
{
[MinMaxRange(80, 120)]
// Will be set to 90-100 by default in inspector
public RangedInt Health = new RangedInt(90, 100);
[MinMaxRange(0, 1)]
public RangedFloat Raito;
}
Limit Vector values set in inspector to a specified range.
Works with Vector2/3 and with VectorInt versions.
[RangeVector(new float[] { -1, -2 }, new float[] { 2, 1 })]
public Vector2 RangedFloat;
These attributes works with numbers and vectors
[PositiveValueOnly]
public Vector2 ScanRange;
[PositiveValueOnly]
public float ChaseSpeed;
Previously I used a lot of Debug.Assert() in Awake to ensure that all desired values are assigned through inspector. Now I just use MustBeAssigned.
It triggers on value types with default values, null refs, empty arrays and strings
[MustBeAssigned]
public MonoBehaviour MyScript;
[MustBeAssigned]
public float MyFloat;
Change visible in Inspector field name:
OverrideLabel("GUID")]
public string InternalGUID;
originally made to fix serialized properties naming issue
Disallow field edit in Inspector.
Might also work just like ConditionalAttribute to make field disabled, based on some other field value.
public float InitialHealth = 100;
[ReadOnly]
public float CurrentHealth;
See also CharactersRange Attribute
Allows to apply Regular Expression rule to the string field
Optionally, you can use several Modes:
// By default, keep only parts of the string that Match the Expression
RegexStringMode.Match
// Remove from the string parts that not match the Expression
RegexStringMode.Replace
// Highlight the field if any of the parts of the string matching the Expression
RegexStringMode.WarningIfMatch
// Highlight the field if some parts of the string not matching the Expression
RegexStringMode.WarningIfNotMatch
Also with the third parameter you can specify RegexOprions for validator
[RegexString(MyRegex.FloatingNumber)]
public string MatchDigit;
[RegexString(@"\d+", RegexStringMode.Replace)]
public string WithoutNumbers;
[RegexString("[a-zA-Z]+", RegexStringMode.WarningIfNotMatch)]
public string Name;
[RegexString(MyRegex.Email, RegexStringMode.WarningIfNotMatch)]
public string Email;
[RequireLayer("Interactive")]
[RequireTag("Acquirable")]
public class PickupItem : MonoBehaviour { ... }
This attributes will set layer and tag of GameObject with such script on playmode.
Changes will persist when you will exit playmode
You may use layer index instead of a name
only works on objects present on scene initially, won't work on objects instantiated during playmode
Use with a string to display a popup of scenes, that listed in BuildSettings
[Scene]
public string SceneA;
Consider to use SceneReference type instead as it keeps scene reference if Scene is renamed
by incredible Ryan Hipple
[SearchableEnum]
public KeyCode SearchableKeyCode;
Also, if you want to make your enum to be searchable by default you can utilize SearchableEnumDrawer by making PropertyDrawer:
public enum TestEnum {A, B, C, D}
// Put CustomDrawer in Editor folder or wrap with ifdef
#if UNITY_EDITOR
[UnityEditor.CustomPropertyDrawer(typeof(TestEnum))]
public class TestEnumDrawer : MyBox.EditorTools.SearchableEnumDrawer {}
#endif
// And use it as usual, without [SearchableEnum]
public TestEnum SearchableField;
Decorative separator. May be with or without the title