Sparrow - is a lightweight system which allows you to show and use references to C# interfaces in Unity Editor via Drag-and-Drop.
Sparrow Interface Field allows you to use Drag-and-Drop approach for C# interface field in Unity Inspector. It provides the possibility to use interfaces in code without more complex dependency injection principles. Now it is possible to use the interface fields references in a classic manner with the Drag-and-Drop like reference to an average class.
Besides this, Sparrow provides a mechanism of fast and easy initialization for every interface field. Beside a classic Drag-and-Drop, there are three initialization modes: Auto Initialization, Search in child components and Search in scene components.
Features:
Classic Drag-and-Drop approach for C# interface initialization in Unity Inspector;
Fast search target component with auto initialization mode in child components;
Easily search target in child components with fast initialization mode;
Easily search target in all scene components with fast initialization mode;
Support arrays and container classes;
Support Scriptable Objects;
Support two work modes: via attributes and via special wrapper class.
Support all platforms.
Support Unity 2019.4 and higher.
Read Documentation to configure the system for work with Unity 2020 and prior versions.
First of all add Sparrow namespace:
CorD.SparrowInterfaceField
Next, to use Sparrow Interface Field, you need to declare a variable which will store reference to a target class. You can do this in two ways:
You need declare variable like this:
[SerializeField]
InterfaceField<Т> fieldName;
//Where T is target interface
//fieldName - name of an Interface Field variable
Interface “ISomeInterface'' is an example of a simple interface.
After declaring a variable, you can access the interface using the Get() method and use the target interface instance in your code. For convenience, the properties Value and i (i - interface) are introduced, which are equivalent to the Get() method.
You need declare variable like this:
[SerializeField, InterfaceField(typeof(T))]
Object someInterfacefield;
//Where T is target interface
//someInterfacefield - name of an Interface Field base variable
In general, these methods give the same results. However, in most cases, a wrapper class may be preferable, as it provides get and initialization methods.
Using of the attribute is reasonable if you do not want to have explicit dependencies on Sparrow.
For convenience, you can declare properties for reading, which converts the type to the desired one:
For Wrapper:
[SerializeField]
InterfaceField<ISomeInterface> someInterfaceField;
ISomeInterface SomeInterfaceField => someInterfaceField.Value;
For Attribute:
[SerializeField, InterfaceField(typeof(ISomeInterface))]
Object someInterfaceFieldAttribute;
ISomeInterface SomeInterfaceFieldAttribute => someInterfaceFieldAttribute as ISomeInterface;
This is especially recommended when using the Attribute variant, as unlike the Wrapper, there are no getter convenience methods.
After declaring a variable, regardless of the method, you will see the standard drag and drop field in the unit editor, which is complemented by three buttons. When you hover over the field name, the required interface is displayed.
You can use the classic initialization mechanism by dragging the target class right in the editor. If the class is correct, it will be saved in this field, the dependency is set. Source code of Description Processor and Descriptor Component can be found in the Examples folder. Otherwise, the Interface Field value will be set to None (null), an error message will be displayed in the console.
Important!
Only MonoBehaviour or ScriptableObject components can be used to initialize an interface field.
Buttons are needed to speed up work when initializing fields, because Drag And Drop is not always convenient.
А - Automatic initialization. When you click on this button, a suitable component is searched for on the current object, if not found, in child gameobjects. If a suitable component is found, it is assigned to this field. Otherwise, an error message is displayed and this field is set to None (null).
Search for the target component on the given object and its children. Serves to select the required component if the target interface is implemented by several components attached to this GO. When the button is clicked, a list of all components located on the given object and in its children that implement the target interface appears. There is also a None item, which is used to reset the current value.
Searches for the target component in the current scene. It is an analogue of the classic Object Picker. When you click on the button, a list of all the components on the stage that implement the target interface appears. There is also a None item, which is used to reset the current value.
Important!
Buttons : and # can be used to conveniently reset the current value set in the field.
You can also use a default object picker. However, due to the peculiarities of the system operation, it may be advisable to use the Object Picker only for assigning ScriptableObjects whose names you know. This is due to the fact that the object picker will display all available objects on the stage and in the project folder, regardless of whether they fit or not.
This section applies to the Wrapper Interface Field.
When working with an interface field in code, you can assign values to the field using the Set() method.
Also a TryInitInterface() method can be used. It tries to find the target component in the given game object. In case a component is not found it tries to find it in children of the given game object. Can be handy for quick code initialization instead of using Drag And Drop or GetComponent().
You can set the Object field to the target component from code, if necessary, using an assignment. However, this is not convenient, so in such situations it is advisable to use the wrapper.
When creating an interface field, only interfaces or MonoBehaviour classes can be used as a type. If you try to set a different type, an error message will be displayed.
Sparrow Interface Field fully supports working with prefabs. When switching to the prefab editing mode, the operation of the “Search in current scene” button is blocked, since the prefab cannot refer to an object in a particular scene.
Important!
When working with prefabs, to avoid unintended behavior, it is necessary to switch to editing the prefab in isolation mode. When switching to the prefab context editing mode, if the prefab instance was changed, due to the peculiarities of Unity, the value of the interface field from the instance, and not from the prefab, will be displayed, which may lead to incorrect saving.
Important!
To run Sparrow Interface Field on Unity prior to 2021, you must use the DLL from the Old Unity Version Support folder. This folder contains a DLL compiled for use with older versions of Unity. To start using it, you need to set the following flags: Auto Reference, Validate References, Editor. In turn, on a DLL compiled for new versions of Unity, you need to remove these flags or completely delete this DLL.
On older versions of Unity, there are no methods for determining the stage of work with the prefab. Therefore, when using a DLL for older versions, the component search button in the current scene will not be blocked.