如何在Unity中将对象序列化为JSON

时间:2019-01-23 12:32:53

标签: c# unity3d serialization json-serialization

我正在尝试使用嵌套类,AudioClip和texture2D序列化一个巨大的Class。我实现了ISerializable接口,并用SerializableAttribute标记了所有类。我使用JsonUtility转换为Json并返回。

除Textures2D,Textures2D []和AudioClip之外,其他所有工具都运行良好。 ISerializable方法的实现如下:

[Serializable]
public class Illustration : ISerializable
{
    public Texture2D Image = new Texture2D(256, 256);

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(nameof(Image), Image.EncodeToPNG(), typeof(byte[]));
    }

    private Illustration(SerializationInfo info, StreamingContext context)
    {
        Image.LoadImage(info.GetValue(nameof(Image), typeof(byte[])) as byte[]);
    }
}

[Serializable]
public class CustomAnimation : ISerializable
{
    public Texture2D[] Images;

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(nameof(Images), Images.Select(x => x.EncodeToPNG()).ToArray(), typeof(byte[][]));
    }

    private CustomAnimation(SerializationInfo info, StreamingContext context)
    {
        var textures = info.GetValue(nameof(Images), typeof(byte[][])) as byte[][];
        if (textures != null)
        {
            var imagesAndTextures = Images.Zip(textures, (i, t) => new {Images = i, textures = t});
            foreach (var it in imagesAndTextures)
            {
                it.Images.LoadImage(it.textures);
            }
        }
    }
}

我希望这段代码能够使用Textures的字节数组生成JSON,但是我明白了:

"Illustrations": [
                {
                    "Image": {
                        "instanceID": 34540
                    }
                }
]

为什么我有这个instanceID?我需要二进制纹理将其保存在文本文件中。它不是运行时对象。

3 个答案:

答案 0 :(得分:2)

将纹理存储为json中的字节数组不是一个好主意,没有人这样做,并且一定有原因。

如果确实需要,那么就需要纹理中的字节数组,最有可能是jpeg,因此它更小:

byte [] tex = texture.EncodeToJpg();
var str = System.Text.Encoding.Default.GetString(tex);
JsonObject json = new JsonObject();   // pseudo code for a json parser
json.Add("Illustration", str);

反之亦然:

string str = json.GetString("Illustration");
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);

但是实际上,json只包含图片的网址。

将纹理存储为字符串化字节数组几乎没有什么用处,因为jpg已经是一个txt文件,其中包含最有可能是二进制形式的字节数组。因此,使用第二种方法,您将拆分json并使其实际可读。

答案 1 :(得分:0)

我认为您无法序列化映像本身。它已加载到内存中,并且图像是参考。

另一件事是,如果您更改纹理的任何属性,它将使新的纹理发芽,也失去了原始纹理的引用。

您可以做的是使用纹理名称创建另一个数组,然后在加载JSon时应用。

答案 2 :(得分:0)

您的方法看起来没问题-我认为它失败是因为UnityEngine的内部工作,其中部分数据在托管/ c#端,而部分数据在本机/ c ++端。纹理变得更加复杂,如果纹理被标记为可读的,则纹理既可以存在于GPU上,也可以存在于Ram / GPU中。最糟糕的情况是rendertextures,它们完美地存在于边缘,并且具有一些奇怪的行为(即,即使您松开引用也不会收集到垃圾)。

解决方法似乎很简单-制作一个可序列化的byte []字段,用编码的纹理(或您的zip格式)填充它-甚至可以提前(在序列化之前)。