【问题标题】:Unity deserializing an object in another projectUnity反序列化另一个项目中的对象
【发布时间】:2018-03-19 11:58:51
【问题描述】:

我正在创建一个工具,帮助我工作室中的艺术家轻松设计他们的 UI,然后让他们能够将 UI 导出给开发人员以在他们的项目中使用。

长话短说,我遵循了这个教程:What is the best way to save game state?

当我在同一个脚本中编写所有内容时,它可以正常工作。

但是,当我打开另一个统一项目来导入数据时,它停止了正常工作。它会读取文件,但是应该实例化的 spawnObject 变量保持为空。

我这里使用的类叫做UIdata,它只有一个游戏对象变量inputObject,这个类和我从另一个项目中导出的完全一样

我不太清楚为什么它不工作,如果它从另一个项目导入某些东西,反序列化可以工作吗?

这是我的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Runtime.Serialization;
using System.Xml.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System;
public class DataSaver
{
    public static void saveData<T>(T dataToSave, string dataFileName)
    {
        string tempPath = Application.streamingAssetsPath + "/newUICorrect.txt";
        string jsonData = JsonUtility.ToJson(dataToSave, true);
        byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);

        if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
        }

        try
        {
            File.WriteAllBytes(tempPath, jsonByte);
            Debug.Log("Saved Data to: " + tempPath.Replace("/", "\\"));
        }
        catch (Exception e)
        {
            Debug.LogWarning("Failed To PlayerInfo Data to: " + tempPath.Replace("/", "\\"));
            Debug.LogWarning("Error: " + e.Message);
        }
    }

    public static T loadData<T>(string dataFileName)
    {
        string tempPath = Application.streamingAssetsPath + "/newUICorrect.txt";
        if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
        {
            Debug.LogWarning("Directory does not exist");
            return default(T);
        }

        if (!File.Exists(tempPath))
        {
            Debug.Log("File does not exist");
            return default(T);
        }
        else
        {
            Debug.Log("found file");
        }
        byte[] jsonByte = null;
        try
        {
            jsonByte = File.ReadAllBytes(tempPath);
            Debug.Log("Loaded Data from: " + tempPath.Replace("/", "\\"));
        }
        catch (Exception e)
        {
            Debug.LogWarning("Failed To Load Data from: " + tempPath.Replace("/", "\\"));
            Debug.LogWarning("Error: " + e.Message);
        }

        string jsonData = Encoding.ASCII.GetString(jsonByte);

        object resultValue = JsonUtility.FromJson<T>(jsonData);
        return (T)Convert.ChangeType(resultValue, typeof(T));
    }
}

[System.Serializable]
public class UIData
{
    public GameObject inputObject;
}

public class LoadingScript : MonoBehaviour
{
    private GameObject objectToSpawn;
    void Start()
    {

    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.I))
        {
            importObject();
        }
    }
    public void importObject()
    {
        UIData loadedData = new UIData();
        loadedData = DataSaver.loadData<UIData>("UI");
        objectToSpawn = loadedData.inputObject;


        if (loadedData == null)
        {
            return;
        }
        print(objectToSpawn);
    }
}

【问题讨论】:

  • inputObject 变量是一种游戏对象,而您 cannot 序列化游戏对象。您可以在 UIData 类中添加有关附加到 GameObject 的类的信息和相关信息,然后对其进行序列化
  • 您对此很确定,因为当我序列化一个对象并在另一个脚本上反序列化它时,我得到了它的工作,但由于某种原因它不适用于另一个项目。更不用说,我在上面发布的示例谈到了序列化我认为的对象的可能性
  • 你不能序列化一个游戏对象。 inputObject 是一个游戏对象...

标签: class unity3d serialization deserialization loading


【解决方案1】:

@Programmer 是正确的,you cannot serialize engine types。有几种方法可以解决您的问题。第一种是通过以下方式(伪代码)序列化其 MonoBehaviour 组件来重建您的游戏对象:

public GameObject TestSaveAndLoadComponent(MyMonoBehaviour myComponent, GameObject objectToLoadComponentOnto){
        // convert component to Json
        string jsonString = JsonUtility.ToJson(myComponent);

        // Pretend to save the json string to File
        string directory = "TestDirectory";
        string file = "objectFile";
        SaveLoadData.SaveString(directory,file,objectJson);

        // load string from file
        string loadString = SaveLoadData.LoadString(directory,file);

        // add a MonoBehaviour component to the object so that it can be
        // overwritten by the JsonUtility
        MyMonoBehaviour componentToOverwrite = objectToLoadComponentOnto.AddComponent<MyMonoBehaviour>();
        JsonUtility.FromJsonOverwrite(loadString, componentToOverwrite);

        return newObject;
}

JsonUtility 可能无法提供您的 monoBehaviour 类的深层副本,我用得不多。它非常简单,如果它不能满足您的需求,总有Json.Net for unity

话虽如此,如果您使用模型-视图-控制器模式以正确的方式构建代码,则不需要序列化游戏对象或单一行为。在这种情况下,您只需序列化为 UI 定义模型的非常简单的类,然后您的视图类将在给定模型的单独场景或项目中重建 ui。

【讨论】:

  • 好吧,我没有使用模型,我只使用 ui 图像游戏对象。而且,也许我想念你,如果我是的话,我很抱歉。但是在序列化游戏对象并在同一个项目中反序列化它时,我已经使用上面的方法让它工作了。它仅在序列化游戏对象并在单独的项目中反序列化时停止工作,尽管使用相同的代码。
  • 'print(objectToSpawn);'在您的 ImportObject 函数中不返回 null?
  • 我怀疑发生的事情是在您的原始项目中,您没有使用文件中的“已保存”游戏对象,而是使用了对场景中对象或其他地方的引用那个项目。当您移动到不同的项目时,您正在尝试实际使用保存的游戏对象,但它不起作用,因为您无法序列化游戏对象。尝试在一个非常简单的测试中序列化和反序列化游戏对象字段。我刚刚完成了,在我的 Json 保存文件中它只是写着:“null”
  • 所以对于那些项目我使用了完全相同的代码,唯一的区别是我最后写的第一个代码:gameobject afterImport = loadeddata.inputobject。它成功了,它甚至在编辑器中显示该对象不再为空。对于第二个项目,我唯一更改的行是 objectToSpawn = loadeddata.inputobject。打印(对象生成)。确实,我在开始时将游戏对象加载为参考,以便对其进行序列化。但就是这样,我根本没有触摸输入对象,代码是一样的。
  • 哦,对不起。我的错,正在查看错误的文件。我的测试保存内容为: {"inputObject":{"instanceID":0}} 所以它没有序列化游戏对象本身,JsonUtility 将 ID 引用标签序列化到场景中的游戏对象。这可以解释为什么它在一个项目中有效,而在另一个项目中无效。 JsonUtility 只是试图在反序列化时分配场景引用,当它没有找到它时,输出为空。今天学到了一些新东西:)。希望现在一切都说得通了。
猜你喜欢
  • 2015-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-02
  • 2017-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多