简体   繁体   English

有什么方法可以将引用的MonoBehaviours序列化为JSON?

[英]Is there any way to serialize referenced MonoBehaviours to JSON?

Let's say I have an object called ObjectA which contains two objects: ObjectsB and ObjectC . 比方说,我有一个名为对象ObjectA包含两个对象: ObjectsBObjectC

[System.Serializable]
public ClassA
{
    public ClassB classB;
    public ClassC classC;

    public ClassA()
    {
        classB = new ClassB();
        classC = new ClassC();
    }
}

[System.Serializable]
public ClassB
{
    //Some fields.
}

[System.Serializable]
public ClassC
{
    //Some fields.
}

If I serialize ObjectA to JSON, ObjectB and ObjectC don't get serialized. 如果我将ObjectA序列化为JSON,则ObjectBObjectC不会序列化。 This is what I've got after serializing ObjectA to JSON: 这是将ObjectA序列化为JSON之后的结果:
{"_instanceB":{"instanceID":10480},"_instanceC":{"instanceID":10230}}
I need to serialize all these objects to a file and save it locally on hard drive to be able to restore their states later. 我需要将所有这些对象序列化为文件,并将其本地保存在硬盘驱动器上,以便以后恢复它们的状态。 How can I do it? 我该怎么做?
Am I supposed to retrieve ClassB and ClassC from ClassA then serialize and save them individually? 我是否应该从ClassA检索ClassBClassC ,然后分别进行序列化和保存? Something like this: 像这样:

public void Save()
{
    //Get instances of ClassB and ClassC.
    ClassB classB = classA.GetClassB;
    ClassC classC = classA.GetClassC;

    //Generate different JSON for each class.
    string classA_JSON = JsonUtility.ToJson(classA);
    string classB_JSON = JsonUtility.ToJson(classB);
    string classC_JSON = JsonUtility.ToJson(classC);

    //Paths for saving locally.
    string pathForClassA = Path.Combine("C:\\", "classA.json");
    string pathForClassB = Path.Combine("C:\\", "classB.json");
    string pathForClassC = Path.Combine("C:\\", "classC.json");

    File.WriteAllText(pathForClassA, classA_JSON);
    File.WriteAllText(pathForClassB, classB_JSON);
    File.WriteAllText(pathForClassC, classC_JSON);
}

Looks ugly and it will generate a new JSON file for each nested class. 看起来很丑,它将为每个嵌套类生成一个新的JSON文件。 Can I somehow serialize ClassA including its nested classes into one JSON file? 我可以以某种方式将包括嵌套类的ClassA序列化为一个JSON文件吗?

PS This is a Unity project and ClassA , ClassB , and ClassC derive from MonoBehaviour . PS这是一个Unity项目, ClassAClassBClassC源自MonoBehaviour Since BinaryFormatter doesn't support MonoBehaviour I can't use it. 由于BinaryFormatter不支持MonoBehaviour ,因此无法使用它。 The only thing that left for me is to serialize it to JSON. 剩下的唯一一件事就是将其序列化为JSON。

Can I somehow serialize ClassA including its nested classes into one JSON file? 我可以以某种方式将包括嵌套类的ClassA序列化为一个JSON文件吗?

Yes you could but it would require some work: 是的,您可以,但是需要一些工作:

You could have [Serializable] representation classes for ClassB and ClassC and use the ISerializationCallbackReceiver interface for filling and using them in ClassA 您可以为ClassBClassC使用[Serializable]表示形式类,并使用ISerializationCallbackReceiver接口ClassA进行填充和使用

Something like eg 像例如

public class ClassB : MonoBehaviour
{
    [SerializeField] private float example1;
    [SerializeField] private string example2;
    // etc.

    public void SetUp(SerializableClassB values)
    {
        // set all values
        this.example1 = values.example1;
        this.example2 = values.example2;
        // etc.
    }

    public SerializableClassB GetSerializable()
    {
        var output = new SerializableClassB();

        output.example1 = this.example1;
        output.example2 = this.example2;
        // etc.

        return output;
    }
}

[Serializable]
public class SerializableClassB
{
    public float example1;
    public string example2;
    // etc
}

And the same for ClassC ClassC相同

public class ClassC : MonoBehaviour
{
    [SerializeField] private float example3;
    [SerializeField] private string example4;
    // etc.

    public void SetUp(SerializableClassC values)
    {
        // set all values
        example3 = values.example3;
        example4 = values.example4;
        // etc.
    }

    public SerializableClassC GetSerializable()
    {
        var output = new SerializableClassC();

        output.example3 = example3;
        output.example4 = example4;
        // etc.

        return output;
    }
}

[Serializable]
public class SerializableClassC
{
    public float example3;
    public string example4;
    // etc
}

Then in ClassA you can do 然后在ClassA您可以

public class ClassA : MonoBehaviour, ISerializationCallbackReceiver
{
    public ClassB _classB;
    public ClassC _classC;

    [SerializeField] private SerializableClassB _serializableClassB;
    [SerializeField] private SerializableClassC _serializeableClassC;


    public void OnBeforeSerialize()
    {
        // before writing to a Json get the information from the MonoBehaviours into the normal classes
        if(_classB) _serializableClassB = _classB.GetSerializable();
        if(_classC) _serializeableClassC = _classC.GetSerializable();

    }

    public void OnAfterDeserialize()
    {
        // after deserializing write the infromation from the normal classes into the MonoBehaviours
        if(_classB) _classB.SetUp(_serializableClassB);
        if(_classC) _classC.SetUp(_serializeableClassC);
    }
}

The second huge advantage (side-effect) is that now you additionally can also controll the values of _classB and _classC directly on the ClassA instance. 第二个巨大的优势(副作用)是,现在您还可以直接在ClassA实例上控制_classB_classC的值。 This way you can modify MonoBehaviour values in a centralized manager class. 这样,您可以在集中管理器类中修改MonoBehaviour值。

在此处输入图片说明

After serializing to json using 使用序列化为json后

private void Start()
{
    File.WriteAllText(Path.Combine(Application.streamingAssetsPath, "Test.txt"), JsonUtility.ToJson(this));
    AssetDatabase.Refresh();
}

you now get 你现在得到

{
    "_classB":{"instanceID":-6766},"_classC":{"instanceID":-6826},
    "_serializableClassB": {
            "example1":23.0,
            "example2":"54ththfghg"
    },
    "_serializeableClassC": {
            "example3":67.0,
            "example4":"567gffhgfhgf"
    }
}

Than for the example I changed it to 比起示例,我将其更改为

{
    "_classB":{"instanceID":-6766},"_classC":{"instanceID":-6826},
    "_serializableClassB": {
            "example1":47,
            "example2":"Hello"
    },
    "_serializeableClassC": {
            "example3":32.123,
            "example4":"World!"
    }
}

and deserialized on start from json using 并从json开始使用

private void Start()
{
    JsonUtility.FromJsonOverwrite(File.ReadAllText(Path.Combine(Application.streamingAssetsPath, "Test.txt")), this);
}

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM