Unity:将精灵保存/加载为 Json

Posted

技术标签:

【中文标题】Unity:将精灵保存/加载为 Json【英文标题】:Unity: Saving/Loading Sprites as Json 【发布时间】:2017-11-03 13:38:23 【问题描述】:

我正在学习一个需要保存属于某个对象的精灵的教程。 我正在创建一个项目数据库,当然希望该项目附带正确的图像。这就是我建立我的项目数据库的方式:

项目对象

[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;


然后我保存/加载 ItemData.itemList。这很好用。如您所见,我使用“slug”来加载我的项目的精灵,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?

【问题讨论】:

不应该在游戏中保存精灵。您应该使用 AssetBundles 或 Resources API。至于保存,保存AssetBundles的path或者Resources文件夹 @Programmer 谢谢,我暂时保存资源文件夹的路径。并开始研究 AssetBundles。 【参考方案1】:

如果您使用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。通过这种方式,您可以轻松引用 U​​nityEngine 对象,而无需使用 Resources 文件夹(除非必要,否则不推荐使用)。

【讨论】:

谢谢,+1 提到 ScriptableObjects。但据我了解,这些都是在内部保存的。而且我希望玩家能够在没有太多问题的情况下修改我的游戏。哪个 Json 非常适合 这是我尝试使用的方法,但不幸的是,您无法在 OnAfterDeserialize 或 OnBeforeSerialize 期间调用 Resources.Load。【参考方案2】:

更合适的方法是将纹理保存为字节 [],然后您的 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));

【讨论】:

接受了,因为它回答了我的问题。但是我将只保存资源资产的路径:)

以上是关于Unity:将精灵保存/加载为 Json的主要内容,如果未能解决你的问题,请参考以下文章

在 Unity 中来自 spritesheet 的动画异相

Unity - 如何掩盖精灵网格内的精灵?

Unity3D动态纹理加载与精灵创建

Unity像素艺术多个精灵没有正确切割

关于Unity中的NGUI精灵

为 Unity-2D 创建精灵表