by Tarocco
Unity does not serialize properties or any static members. You have some options for serializing member fields.
- Public fields of serializable types are automatically serialized and show in the Unity Editor
- Non-public fields of serializable types are only serialized when using the
[SerializeField]
attribute
Here are some examples of different data-hiding options:
public int ClipsRemaining; // Serialized, shown in the inspector editor window, and accessible to other objects
[HideInInspector]
public int AmmoCount; // Serialized, hidden in the inspector editor window, and accessible to other objects
[SerializeField]
private float BulletSpeed; // Serialized, shown in the inspector editor window, and inaccessible from other objects
[SerializeField]
[HideInInspector]
private float FireRate; // Serialized, hidden from the inspector editor window, and inaccessible from other objects
private float FlashBrightness; // Non-serialized, hidden from the inspector editor window, and accessible from other objects
[NonSerialized]
[HideInInspector]
public float Holdover; // Non-serialized, hidden from the inspector editor window, and accessible to other objects
// There are no combinations for Non-serialized + shown in the inspector editor window
Unity does not serialize auto-properties. Use the property backing field pattern to make properties with serialized field values. My recommendation for backing field nomenclature is to use a prefix underscore.
[SerializeField]
private float _Speed = 5f;
public float Speed
{
get { return _Speed; }
set { _Speed = Mathf.Max(0f, value); } // Only positive values allowed
}
By having the declaring class implement the ISerializationCallbackReceiver
interface, it is possible to define constraints, or better yet, use polymorphism in the Unity Editor with editor-side preconditions.
IFooBarLike.cs
public interface IFooBarLike
{
int Foos { get; set; }
int Bars { get; set; }
}
FooBarBazBongo.cs
using UnityEngine;
public class FooBarBazBongo : MonoBehavior, IFooBarLike
{
[SerializeField]
private int _Foos = 1;
public int Foos { get { return _Foos; } set { _Foos = value } }
[SerializeField]
private int _Bars = 1;
public int Bars { get { return _Bars; } set { _Bars = Mathf.Max(Foos, _value) } }
}
MyBehavior.cs
using UnityEngine;
public class MyBehavior : MonoBehaviour, ISerializationCallbackReceiver
{
[SerializeField]
private MonoBehaviour _FooBar;
public IFooBarLike FooBar
{
get { return (IFooBarLike)_FooBar; }
private set { _FooBar = (MonoBehaviour)value; }
}
public void OnBeforeSerialize()
{
// "Round-trip" properties to enforce preconditions
// during serialization in the Unity Editor
FooBar = FooBar;
}
public void OnAfterSerialize() { } // A vestigial organ
}
This allows you to have inspector editor fields that can be assigned to any MonoBehaviour
as long as it implements the IFooBarLike
interface, and is represented with the correct interface type by the property, accessible by other objects. The get
accessor is public, but the set
accessor has been set private. This is an advantage of using properties instead of plain fields.
To allow Unity to serialize events in the editor, (and conveniently show them in the inspector editor window), you can use the property backing field technique. Nope that you will need to use the [Serializable]
attribute on your UnityEvent
-derived class.
HopEvent.cs
using System;
using UnityEngine;
using UnityEngine.Events;
public class HopEventArgs : EventArgs
{
public Vector3 Impulse;
}
[Serializable]
public class HopEvent : UnityEvent<object, HopEventArgs> { }
MyBunny.cs
using UnityEngine;
using UnityEngine.Events;
public class MyBunny : MonoBehaviour
{
[SerializeField]
private HopEvent _Hop;
public event UnityAction<object, HopEventArgs> Hop
{
add { _Hop.AddListener(value); }
remove { _Hop.RemoveListener(value); }
}
}
Now if you have a script to handle the behavior of bunny ears when the bunny hops...
BunnyEar.cs
using UnityEngine;
public class BunnyEar : MonoBehaviour
{
public Transform[] WiggleBones;
public void HandleHop(object sender, HopEventArgs args)
{
// Do something
}
}
...you can assign the HandleHop
methods to the Hop
event in the Unity Editor as a UnityEvent
, or at runtime as a regular C# event!