- Home /
How to make decimal variables visible in Inspector?
I want to change a decimal variables in runtime in the inspector or just watch it without using
Debug.Log(variable);
Is this anyhow possible?
It's a public variable already, but it's still not visible in the inspector. And yes i use c#.
public decimal playtime = 0$$anonymous$$;
Hi, I think Unity can't serialize the decimal type, that's why you can't see it in the inspector. Float and double are supported but if you have to use decimal, I think you can write your own serializer for it to work in Unity. You can also write custom inspectors or PropertyDrawer that could help display/edit this type, like it's done here: http://wiki.unity3d.com/index.php/EnumFlagPropertyDrawer
I have tried to make a serialize container but still the decimals wont show up.
[System.Serializable]
public class Decimals
{
public decimal playtime, bla, blu;
}
public class Game$$anonymous$$anagerScript : $$anonymous$$onoBehaviour
{
public Decimals showall;
}
Also my program$$anonymous$$g skills aint that good.
Well, what you wrote is correct to serialize a custom class non derived from $$anonymous$$onobehavior. The problem here is that Unity can't serialize the decimal type at all. Finding a way to serialize this type is more complicated, you can read this blog about Unity serialization here: http://blogs.unity3d.com/2014/06/24/serialization-in-unity/ . They give an example of custom serialization and information on how to do this. This is not an quick/easy task, maybe some scripts in the asset store already manage this case. $$anonymous$$ay I ask why you want to use decimal type ?
Hmm i see, to bad it's not implemented yet. $$anonymous$$aybe in a future update or stuff.
I need to handle big numbers for my current project. So decimals are the best choice here it seems.
I work on an Idle Game where i get alot money in mid game+ and also have to spend it. Where floats and longs are to short to handle i use decimals which can hold 28-29 digits.
Answer by Bunny83 · Oct 13, 2014 at 06:52 PM
Like dns said, Unity can't serialize the decimal type on it's own. If you want Unity to actually "store" (serialize) the value, you have to provide your own way to serialize the value. This wrapper class does this:
//SerializableDecimal.cs
using UnityEngine;
using System.Collections;
[System.Serializable]
public class SerializableDecimal : ISerializationCallbackReceiver
{
public decimal value;
[SerializeField]
private int[] data;
public void OnBeforeSerialize ()
{
data = decimal.GetBits(value);
}
public void OnAfterDeserialize ()
{
if (data != null && data.Length == 4)
{
value = new decimal(data);
}
}
}
The field "value" is what you would use at runtime. Whenever Unity wants to serialize this custom class, it first copies the 4 internal uint fields into fields that unity can serialize. Now Unity will store those 4 values which made up a decimal value. When deserializing it restores those values.
Of course the inspector can only "show" serialized data, so it will show by default the data array with the 4 internal fields (hi, mid, lo and flags) which are difficult to edit. To get a visual representation you have to provide a PropertyDrawer like this:
//SerializableDecimalDrawer.cs
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(SerializableDecimal))]
public class SerializableDecimalDrawer : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
var obj = property.serializedObject.targetObject;
var inst = (SerializableDecimal)this.fieldInfo.GetValue(obj);
var fieldRect = EditorGUI.PrefixLabel(position, label);
string text = GUI.TextField(fieldRect, inst.value.ToString());
if (GUI.changed)
{
decimal val;
if(decimal.TryParse(text, out val))
{
inst.value = val;
property.serializedObject.ApplyModifiedProperties();
}
}
}
}
With those two classes you have a decimal type that is serialized and can be edited / viewed in the inspector.
Keep in mind that the PropertyDrawer class need to be inside an "/Editor/" folder since it's an editor class.
edit
Just noticed that i probably should also give a usage example ;) Here it is:
public class DecimalTestScript : MonoBehaviour
{
public SerializableDecimal val;
void Start ()
{
Debug.Log("Val: " + val.value);
}
}
So the only difference from using a "normal" decimal value is, that you have to use:
val.value
instead of
val
Of course you can implement implicit and explicit cast operators to use a SerializableDecimal just like a decimal, but such operators don't work in all cases.
Wow thanks alot for that much effort, i didn't expect so much trouble with such small task. I thought it would be way easier. I may test it out later.
I just realized i had a copy&paste error ^^ I somehow inserted the same script twice. I've updated the scripts. I also searched a bit the documentation and found the GetBits method, so there's no need for using reflection. Now the SerializableDecimal class is much shorter.
Cool, that's a nice and short example of a custom serialization with PropertyDrawer! This could also go on the Wiki as ISerializationCallbackReceiver was introduced with Unity 4.5 and is not very well documented yet!
Ok, now, what about this new Quantum bit type ? ;-)
Answer by coderD1mka · Nov 16, 2020 at 06:41 PM
It does not work if I use SerializableDecimal class within a ScriptableObject inherited class =(
I had a similar issue trying to get this solution to work inside ScriptableObjects, but then figured out I couldn't really use property drawers altogether in my case, so came up with a workaround that works for really any numeric data type not supported natively by Unity's serializer. The solution isn't perfect but it works :)
[System.Serializable]
public class SerializableDecimal : ISerializationCallbackReceiver
{
[SerializeField] private string inspectorField = "0";
[HideInInspector] public decimal value;
public void OnBeforeSerialize() {}
public void OnAfterDeserialize()
{
if (!decimal.TryParse(inspectorField, out value))
inspectorField = "0";
}
}