如何在 Unity 中将对象序列化为 JSON
How to serialise Object to JSON in Unity
我正在尝试使用嵌套 类、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);
}
}
}
}
我希望此代码生成一个 JSON 与纹理的字节数组,但我得到这个:
"Illustrations": [
{
"Image": {
"instanceID": 34540
}
}
]
为什么我有这个instanceID?然后我需要二进制纹理将其保存在文本文件中。它不是运行时对象。
我认为你不能序列化图像本身。已载入内存,图片供参考
另一件事是,如果您更改任何 属性 纹理,它将生成一个新纹理,同时也会丢失原始纹理的引用。
您可以做的是使用纹理名称创建另一个数组,然后在加载 JSon.
时应用
您的方法看起来不错 - 我认为它失败是因为 UnityEngine 的内部工作原理,其中部分数据位于 managed/c# 侧,部分数据位于 native/c++ 侧。纹理变得更加复杂,如果它们被标记为可读,它们可以存在于 GPU 上或两者都存在于 Ram/GPU 中。最奇怪的情况是 rendertextures,它完美地生活在边缘,并且有一些奇怪的行为(即即使你丢失引用它们也不会收集垃圾)。
解决方法似乎很简单 - 制作一个可序列化的 byte[] 字段,用编码纹理填充它(或你做的 zip) - 甚至可能提前(在序列化之前)。
在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 仅包含图像的 url。
将纹理存储为字符串化字节数组没有什么意义,因为 jpg 已经是包含字节数组的 txt 文件,很可能是二进制文件。因此,使用第二种方法,您将拆分 json 并使其真正可读。
我正在尝试使用嵌套 类、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);
}
}
}
}
我希望此代码生成一个 JSON 与纹理的字节数组,但我得到这个:
"Illustrations": [
{
"Image": {
"instanceID": 34540
}
}
]
为什么我有这个instanceID?然后我需要二进制纹理将其保存在文本文件中。它不是运行时对象。
我认为你不能序列化图像本身。已载入内存,图片供参考
另一件事是,如果您更改任何 属性 纹理,它将生成一个新纹理,同时也会丢失原始纹理的引用。
您可以做的是使用纹理名称创建另一个数组,然后在加载 JSon.
时应用您的方法看起来不错 - 我认为它失败是因为 UnityEngine 的内部工作原理,其中部分数据位于 managed/c# 侧,部分数据位于 native/c++ 侧。纹理变得更加复杂,如果它们被标记为可读,它们可以存在于 GPU 上或两者都存在于 Ram/GPU 中。最奇怪的情况是 rendertextures,它完美地生活在边缘,并且有一些奇怪的行为(即即使你丢失引用它们也不会收集垃圾)。
解决方法似乎很简单 - 制作一个可序列化的 byte[] 字段,用编码纹理填充它(或你做的 zip) - 甚至可能提前(在序列化之前)。
在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 仅包含图像的 url。
将纹理存储为字符串化字节数组没有什么意义,因为 jpg 已经是包含字节数组的 txt 文件,很可能是二进制文件。因此,使用第二种方法,您将拆分 json 并使其真正可读。