Here's a cool trick you can use:
using UnityEngine.Serialization;
public class SFXClip : ScriptableObject
{
[SerializeField, FormerlySerializedAs("clip")]
private AudioClip _clip;
public virtual AudioClip clip {
get { return _clip; }
set { _clip = value; }
}
// other properties
}
The FormerlySerializedAs
attribute from the UnityEngine.Serializaton
namespace allows you to migrate saved parameters from an old name to a new one.
When the serializer doesn't find a member named _clip
in the saved asset, it will look for one with its old name, clip
. If it finds one, it will use that value for the new field.
When you next open and save your asset, it will be saved under the new name. So this way, you can migrate this field to be a property you can override, with no data loss.
To migrate the data from a field into a list, we need a method to do the data fix-up after the object has been deserialized:
public class SFXClip : ScriptableObject {
[SerializeField] List<AudioClip> audioClips;
[SerializeField, HideInInspector, FormerlySerializedAs("clip")]
AudioClip _legacyClip;
void OnValidate()
{
if (_legacyClip == null) return;
if (!audioClips.Contains(_legacyClip))
audioClips.Add(_legacyClip);
_legacyClip = null;
}
}
This gets called on assets included in a build during the build process, or referenced in an open scene or selected object in the inspector. Once the old data has been successfully updated and saved, you can delete this code - although it's not called in a built executable anyway (only in editor), so it doesn't add significant overhead.