Script fields (marked with [SerializeField] attribute) is popular way to setup script dependecies. Other alternative - using FindComponents or FindObject - look less controlable.
.
Main drawbacks of [SerializeField] setup is flooding script GUI inspector with internal prefab dependices.
.
For example, I have Car prefab with CarControlComponent script, that needs referencies to four car wheels. This script may contain some fields that are usable for prefab setup (like Max/Min speed, Rotation speed, et.c.) and that fields should be accassable by prefab user - but wheel references are constructed for in-prefab needs only and should be “incapsulated”.
.
So, the question: is there any way to hide script inspector fields outside of prefab if script is used in prefab object?
If I understand you correctly, you want to show some serialized fields only if you are in prefab mode (>= Unity 2018.3)?
If so, you can achieve this using an attribute and a property drawer:
// PrefabModeOnlyAttribute.cs, located in your script files
public class PrefabModeOnlyAttribute : UnityEngine.PropertyAttribute { }
//PrefabModeOnlyDrawer.cs, located in an Editor folder
using UnityEngine;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;
[CustomPropertyDrawer( typeof( PrefabModeOnly ) )]
public class PrefabModeOnlyDrawer : PropertyDrawer
{
public override float GetPropertyHeight( SerializedProperty property, GUIContent label )
{
return ( PrefabStageUtility.GetCurrentPrefabStage() == null ) ? 0 : EditorGUI.GetPropertyHeight( property, label );
}
public override void OnGUI( Rect position, SerializedProperty property, GUIContent label )
{
if ( PrefabStageUtility.GetCurrentPrefabStage() == null ) return;
EditorGUI.PropertyField( position, property, label );
}
}
Then, in your CarControlComponent
script:
[SerializeField, PrefabModeOnly]
private GameObject[] wheels;
@Hellium A good start, however this makes the fields visible in other Prefabs as well.
Also there is no support for hiding fields that only make sense outside of the Prefab. (Like: a specific Sprite, Manager, Handler, System, Position, Unique name…)
My solution would be:
PrefabOnlyAttribute.cs:
public class PrefabOnlyAttribute : PropertyAttribute { }
public class InstanceOnlyAttribute : PropertyAttribute { }
Editor/PrefabOnlyDrawer.cs:
[CustomPropertyDrawer(typeof(PrefabOnlyAttribute))]
public class PrefabOnlyDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return property.isInstantiatedPrefab ? 0 : EditorGUI.GetPropertyHeight(property, label);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (property.isInstantiatedPrefab) return;
EditorGUI.PropertyField(position, property, label);
}
}
[CustomPropertyDrawer(typeof(InstanceOnlyAttribute))]
public class InstanceOnlyDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return !property.isInstantiatedPrefab ? 0 : EditorGUI.GetPropertyHeight(property, label);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (!property.isInstantiatedPrefab) return;
EditorGUI.PropertyField(position, property, label);
}
}
MyCode.cs:
// Only needed when editing THIS prefab.
[SerializeField, PrefabOnly] private GameObject[] wheels;
// Always overwritten, never needed when editing THIS prefab.
[SerializeField, InstanceOnly] private string driverName;
Again, thanks to @Hellium for setting me on the right path!