I am working on a more robust and editable resource system for our next game and have hit a small snag.
The resources system is based around the ability to increase/decrease the maximum limit, and for the newest version of the resource editor, I wanted to use Ranges to do this, but the Range definition doesn’t seem to be able to take an external float as an argument, I am hoping I am just doing it wrong, but thought I should ask someone with a little experience using Ranges instead of spend any more time doing it wrong.
The following is located inside a serialisable class.
public string resourceName;
public float amountMax;
[Range(0, amountMax)]
public int amountCounter;
The issue is adding amountMax to the Range definition, I receive the following errors in Unity:
ResourcesScript.cs(11,15): error CS0120: An object reference is required to access non-static member `ResourcesClass.amountMax’
ResourcesScript.cs(11,6): error CS1502: The best overloaded method match for `UnityEngine.RangeAttribute.RangeAttribute(float, float)’ has some invalid arguments
ResourcesScript.cs(11,6): error CS1503: Argument #2' cannot convert
object’ expression to type `float’
Attributes are object independent. They’re part of the definition of the class, not the object. You really can only put things that are constant values, or some static objects (arrays, strings, Type objects) in them. Note that when you pull the attribute via reflection from the Type, no instance of that type needs to exist.
var tp = typeof(SomeType);
var attribs = tp.GetCustomAttributes(typeof(SomeAttributeType), false);
If you want to have a custom range where one value can be set to a value relative to another, create a custom type for that, and then a custom inspector for that type.
Something like this:
[System.Serializable()]
public struct IntRange
{
[SerializeField()]
private int _maxValue;
[SerializeField()]
private int _value;
public int MaxValue
{
get { return _maxValue; }
set {
_maxValue = value;
_value = Mathf.Clamp(_value, 0, _maxValue);
}
}
public int Value
{
get { return _value; }
set { _value = Mathf.Clamp(value, 0, _maxValue); }
}
}
[CustomPropertyDrawer(typeof(IntRange))]
public class IntRangeInspector : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight * 2f;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var r = new Rect(position.xMin, position.yMin, position.width, EditorGUIUtility.singleLineHeight);
var maxProp = property.FindPropertyRelative("_maxValue");
EditorGUI.PropertyField(r, maxProp, "MaxValue");
r = new Rect(r.xMin, r.yMax, r.width, r.height);
var valueProp = property.FindPropertyRelative("_value");
valueProp.intValue = Mathf.Clamp(EditorGUI.IntField(r, "Value", valueProp.intValue), 0, maxProp.intValue);
}
}
NOTE - written here in wysiwyg, completely untested, meant for demonstration.
2 Likes