我正在使用ScriptableObject
资产来存储我的多语言应用程序项目的数据。除我要更改现有数据结构的情况外,此方法效果很好。
就我而言,数据结构如下:
[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/I18NData", order = 1)]
public class I18NData : ScriptableObject
{
public I18NSpriteData[] Sprites;
public I18NTextData[] Texts;
}
[System.Serializable]
public class I18NSpriteData
{
public string Label;
public Sprite SpriteEN;
public Sprite SpriteFR;
public Sprite SpriteSG;
public Sprite SpriteES;
public Sprite SpriteDE;
public Sprite SpriteIT;
}
[System.Serializable]
public class I18NTextData
{
public string Label;
[TextArea]
public string TextEN;
[TextArea]
public string TextFR;
[TextArea]
public string TextSG;
[TextArea]
public string TextES;
[TextArea]
public string TextDE;
[TextArea]
public string TextIT;
}
现在,我在Unity Editor中添加数据,并且一切正常。但是,一旦我对现有数据结构进行了更改,编辑器中的所有数据就会丢失。 ScriptableObject似乎已重置为空状态。
这特别令人讨厌,因为我们正处于开发过程中,并且在此阶段不可避免地要更改数据结构...
您如何避免这种情况?您是否有一些脚本可基于其他文件(例如JSON)生成ScriptableObjects?还是在Unity中有一种简单的方法?
感谢任何提示!
答案 0 :(得分:2)
如果您想重命名序列化字段,但保留数据,则Unity具有一个名为FormerlySerializedAs的属性,它将保留旧的序列化字段名称。
[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/I18NData", order = 1)]
public class I18NData : ScriptableObject
{
[FormerlySerializedAs("Sprites")]
public I18NSpriteData[] Sprites2;
public I18NTextData[] Texts;
}
另一个选择是,您可以将字段设为私有并使用SerializeField属性。然后,您可以随时间自由更改用于访问或修改字段的属性,而不会影响序列化:
[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/I18NData", order = 1)]
public class I18NData : ScriptableObject
{
[SerializeField]
private I18NSpriteData[] Sprites;
public I18NSpriteData[] Sprites2 {
get { return Sprites; }
set { Sprites = value; }
}
[SerializeField]
private I18NTextData[] Texts;
public I18NTextData[] Texts2 {
get { return Texts; }
set { Texts= value; }
}
}
您可能要考虑的另一件事是使用ISerializationCallbackReceiver界面来更好地控制Unity的序列化过程。它提供两种方法,OnBeforeSerialize和OnAfterDeserialize,它们在Unity的序列化和反序列化过程中被调用。
当序列化Unity通常无法处理的复杂结构时(例如字典),这可能更有用,但是根据您要进行的更改的类型,这可能会有所帮助。您可能会用它来在版本之间迁移数据。
答案 1 :(得分:1)
对结构的某些更改总是会导致数据丢失,因此,在确定数据的最终布局之前,您不应填充数据,至少在主要人员方面,统一序列化应支持添加新字段,但无论如何,我都不会依赖它。
您可以使用几种技术来改善工作流程。
[System.Serializable]
public struct I18NTextData
{
public string Label;
public I18NTextDataTranslation[] translations;
}
[System.Serializable]
public struct I18NTextDataTranslation
{
public string lang;
public string content;
}
答案 2 :(得分:1)
您可能正在以使Unity无法以所需的方式解包序列化数据的方式更改数据结构。因此,缺少数据。
如果选择了Force Text
序列化模式,则所有ScriptableObject的序列化都将被序列化为人类可读的格式YAML。
在文本编辑器中读取时,ScriptableObject将看起来像这样:
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9228bfb9e457c5341920079380c382ba, type: 3}
m_Name: Data
m_EditorClassIdentifier:
Sprites:
- Label:
SpriteEN: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0}
SpriteFR: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
SpriteSG: {fileID: 10915, guid: 0000000000000000f000000000000000, type: 0}
SpriteES: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0}
SpriteDE: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0}
SpriteIT: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
Texts:
- Label:
TextEN: "Hello\t"
TextFR: Salut!
TextSG: ????
TextES: Holla!
TextDE: Bratwurst
TextIT: Pizza!
只要掌握了YAML,您就可以手动更改数据以适应新的数据结构。