Since you are not able to store 2 variables into the same field (you want to store the bool and the float/Vector3 in one field), there is only one workaround i can think of. You only store the value and if the value is not the same as the default value, the toggle is set and the input field is visible. If you then set the toggle to off the input field gets greyed out and the input field changes to the default value. The only thing you would notice is that you lose your value, if you set the toggle to off and the toggle will be off , if you enter the default value. Another downside is, that you can only inform the attribute about what the default value is, by the constructor arguments. On this the problem is, that these values has to be constant and a vector is not constant. So this works only for primitives like bool, int, float, string, etc.
If you want the complete behaviour without these two problems you will always have to have 2 variables in your scripts and connect them via attributes. It would be beautiful in the inspector but the code writing would be more ugly.
But for an integer my workaround idea (that would be nice and easy to use) would work like this:
For that you make 2 classes.
First:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This will add a toggle in the inspector to always return to the default value.
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Field)]
public class DefaultValueAttribute : PropertyAttribute
{
public readonly int defaultValue;
public DefaultValueAttribute(int defaultValue)
{
this.defaultValue = defaultValue;
}
}
Secound:
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(DefaultValueAttribute))]
public class DefaultValueAttributeDrawer : PropertyDrawer
{
bool? usingOwnValue = null;
const int toggleWidth = 20;
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
float defaultValue = ((DefaultValueAttribute)attribute).defaultValue;
if (!usingOwnValue.HasValue)
usingOwnValue = defaultValue != prop.intValue;
//Draw the toggle
Rect toggleRect = position;
toggleRect.width = toggleWidth;
usingOwnValue = EditorGUI.Toggle(toggleRect, usingOwnValue.Value);
//Shift the input Rect a bit to the right to not cover the toggle
Rect inputRect = position;
inputRect.x += toggleWidth;
inputRect.width -= toggleWidth;
//Draw the input field
if (usingOwnValue.Value)
{
prop.intValue = EditorGUI.IntField(inputRect, label.text, prop.intValue);
}
else
{
using (new EditorGUI.DisabledScope(true))
{
EditorGUI.IntField(inputRect, label.text, prop.intValue);
prop.intValue = (int)defaultValue;
}
}
}
}
Now you can use the default values in your normal classes on top of the common “SerializeField” like:
public class Test1 : MonoBehaviour
{
[SerializeField, DefaultValue(0)] float newFloat;
[SerializeField, DefaultValue("Hallo")] string newString;
}
If you want this for float’s for example you have to change in the classes the types all to float or you make a switch for all types that it could be, like:
switch(prop.propertyType)
{
case SerializedPropertyType.Integer:
prop.intValue = EditorGUI.IntField(position, text, prop.intValue);
break;
case SerializedPropertyType.Boolean:
prop.boolValue = EditorGUI.Toggle(position, text, prop.boolValue);
break;
case SerializedPropertyType.Float:
prop.floatValue EditorGUI.FloatField(position, text, prop.floatValue);
break;
case SerializedPropertyType.String:
prop.stringValue = EditorGUI.TextField(position, text, prop.stringValue);
break;
default:
EditorGUI.LabelField(position, text, "(not supported)");
break;
}
PS: dont forget to put the PropertyDrawer-class in unity into a folder named “editor”