Unity:Saving/Loading 精灵为 Json
Unity: Saving/Loading Sprites as Json
我正在学习一个教程,其中我需要保存属于某个对象的精灵。
我正在创建一个项目数据库,当然希望项目附带正确的图像。这就是我构建项目数据库的方式:
ItemObject
[System.Serializable]
public class ItemObject{
public int id;
public string title;
public int value;
public string toolTip;
public bool stackable;
public string category;
public string slug;
public Sprite sprite;
public ItemObject(int id, string title, int value, string toolTip, bool stackable, string category, string slug)
{
this.id = id;
this.title = title;
this.value = value;
this.toolTip = toolTip;
this.stackable = stackable;
this.category = category;
this.slug = slug;
sprite = Resources.Load<Sprite>("items/" + slug);
}
项目数据
[System.Serializable]
public class ItemData {
public List<ItemObject> itemList;
}
我然后Save/LoadItemData.itemList。效果很好。如您所见,我使用 "slug" 来加载我的 Item 的 sprite,slug 基本上是一个代码友好的名称(例如:golden_hat),然后我为我的 Sprite 使用了相同的名称。
这也很好用,但是 Unity 保存了 Sprite InstanceID,它总是在启动时改变,所以如果我退出 Unity 并加载我的数据,它会得到错误的图像。
我的Json:
{
"itemList": [
{
"id": 0,
"title": "Golden Sword",
"value": 111,
"toolTip": "This is a golden sword",
"stackable": false,
"category": "weapon",
"slug": "golden_sword",
"sprite": {
"instanceID": 13238
}
},
{
"id": 1,
"title": "Steel Gloves",
"value": 222,
"toolTip": "This is steel gloves",
"stackable": true,
"category": "weapon",
"slug": "steel_gloves",
"sprite": {
"instanceID": 13342
}
}
]
}
所以我猜这样做是行不通的,还有其他方法可以在 Json 中保存 Sprite 吗?还是我每次都必须使用 "slug"?
在运行时加载正确的 Sprite
更合适的方法是将纹理保存为字节 [] 然后你的 json 包含字节 [] 的名称或 url。
{
"id": 1,
"title": "Steel Gloves",
"value": 222,
"toolTip": "This is steel gloves",
"stackable": true,
"category": "weapon",
"slug": "steel_gloves",
"sprite": "steelgloves"
}
然后当您获取 json 时,您将转换为 C# 并查找字节数组。一旦你有了字节数组,你就可以重建精灵:
byte [] bytes = File.ReadAllBytes(path);
Texture2d tex = new Texture2D(4,4);
tex.LoadImage(bytes);
Sprite sp = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f,0.5f));
如果您使用 JsonUtility
进行序列化,您可以实施 ISerializationCallbackReceiver
以接收序列化回调。这样你就可以在对象被反序列化后根据存储的路径加载正确的精灵。您还将避免资源重复。
[Serializable]
public class ItemObject : ISerializationCallbackReceiver
{
public void OnAfterDeserialize()
{
sprite = Resources.Load<Sprite>("items/" + slug);
Debug.Log(String.Format("Loaded {0} from {1}", sprite, slug));
}
public void OnBeforeSerialize() { }
(...)
}
如果你真的想要将精灵直接存储在JSON,考虑序列化从Sprite.texture.GetRawTextureData()
获取的原始纹理数据(可能存储二进制base64 string) 中的数据并在运行时使用 Sprite.Create()
重新创建它。 ISerializationCallbackReceiver
技巧也适用于此。
作为附加说明,如果符合您的要求,请务必考虑放弃基于 JSON 的对象数据库,转而使用 Scriptable Objects。这样您就可以轻松引用 UnityEngine 对象,而不必求助于 Resources 文件夹(除非必要,否则不推荐这样做)。
我正在学习一个教程,其中我需要保存属于某个对象的精灵。 我正在创建一个项目数据库,当然希望项目附带正确的图像。这就是我构建项目数据库的方式:
ItemObject
[System.Serializable]
public class ItemObject{
public int id;
public string title;
public int value;
public string toolTip;
public bool stackable;
public string category;
public string slug;
public Sprite sprite;
public ItemObject(int id, string title, int value, string toolTip, bool stackable, string category, string slug)
{
this.id = id;
this.title = title;
this.value = value;
this.toolTip = toolTip;
this.stackable = stackable;
this.category = category;
this.slug = slug;
sprite = Resources.Load<Sprite>("items/" + slug);
}
项目数据
[System.Serializable]
public class ItemData {
public List<ItemObject> itemList;
}
我然后Save/LoadItemData.itemList。效果很好。如您所见,我使用 "slug" 来加载我的 Item 的 sprite,slug 基本上是一个代码友好的名称(例如:golden_hat),然后我为我的 Sprite 使用了相同的名称。
这也很好用,但是 Unity 保存了 Sprite InstanceID,它总是在启动时改变,所以如果我退出 Unity 并加载我的数据,它会得到错误的图像。
我的Json:
{
"itemList": [
{
"id": 0,
"title": "Golden Sword",
"value": 111,
"toolTip": "This is a golden sword",
"stackable": false,
"category": "weapon",
"slug": "golden_sword",
"sprite": {
"instanceID": 13238
}
},
{
"id": 1,
"title": "Steel Gloves",
"value": 222,
"toolTip": "This is steel gloves",
"stackable": true,
"category": "weapon",
"slug": "steel_gloves",
"sprite": {
"instanceID": 13342
}
}
]
}
所以我猜这样做是行不通的,还有其他方法可以在 Json 中保存 Sprite 吗?还是我每次都必须使用 "slug"?
在运行时加载正确的 Sprite更合适的方法是将纹理保存为字节 [] 然后你的 json 包含字节 [] 的名称或 url。
{
"id": 1,
"title": "Steel Gloves",
"value": 222,
"toolTip": "This is steel gloves",
"stackable": true,
"category": "weapon",
"slug": "steel_gloves",
"sprite": "steelgloves"
}
然后当您获取 json 时,您将转换为 C# 并查找字节数组。一旦你有了字节数组,你就可以重建精灵:
byte [] bytes = File.ReadAllBytes(path);
Texture2d tex = new Texture2D(4,4);
tex.LoadImage(bytes);
Sprite sp = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f,0.5f));
如果您使用 JsonUtility
进行序列化,您可以实施 ISerializationCallbackReceiver
以接收序列化回调。这样你就可以在对象被反序列化后根据存储的路径加载正确的精灵。您还将避免资源重复。
[Serializable]
public class ItemObject : ISerializationCallbackReceiver
{
public void OnAfterDeserialize()
{
sprite = Resources.Load<Sprite>("items/" + slug);
Debug.Log(String.Format("Loaded {0} from {1}", sprite, slug));
}
public void OnBeforeSerialize() { }
(...)
}
如果你真的想要将精灵直接存储在JSON,考虑序列化从Sprite.texture.GetRawTextureData()
获取的原始纹理数据(可能存储二进制base64 string) 中的数据并在运行时使用 Sprite.Create()
重新创建它。 ISerializationCallbackReceiver
技巧也适用于此。
作为附加说明,如果符合您的要求,请务必考虑放弃基于 JSON 的对象数据库,转而使用 Scriptable Objects。这样您就可以轻松引用 UnityEngine 对象,而不必求助于 Resources 文件夹(除非必要,否则不推荐这样做)。