如何在Unity中序列化和保存GameObject

时间:2016-04-25 22:27:25

标签: c# unity3d

我有一个游戏,玩家拿起武器然后将其作为GameObject变量放置到我的玩家名为" MainHandWeapon"而我正试图通过场景变化来保存这种武器,所以我试图保存它。我如何处理如下:

public class Player_Manager : Character, Can_Take_Damage {

    // The weapon the player has.
    public GameObject MainHandWeapon;

    public void Save()
    {
        // Create the Binary Formatter.
        BinaryFormatter bf = new BinaryFormatter();
        // Stream the file with a File Stream. (Note that File.Create() 'Creates' or 'Overwrites' a file.)
        FileStream file = File.Create(Application.persistentDataPath + "/PlayerData.dat");
        // Create a new Player_Data.
        Player_Data data = new Player_Data ();
        // Save the data.
        data.weapon = MainHandWeapon;
        data.baseDamage = BaseDamage;
        data.baseHealth = BaseHealth;
        data.currentHealth = CurrentHealth;
        data.baseMana = BaseMana;
        data.currentMana = CurrentMana;
        data.baseMoveSpeed = BaseMoveSpeed;
        // Serialize the file so the contents cannot be manipulated.
        bf.Serialize(file, data);
        // Close the file to prevent any corruptions
        file.Close();
    }
}

[Serializable]
class Player_Data
{
    [SerializeField]
    private GameObject _weapon;
    public GameObject weapon{
        get { return _weapon; }
        set { _weapon = value; }
    }

    public float baseDamage;
    public float baseHealth;
    public float currentHealth;
    public float baseMana;
    public float currentMana;
    public float baseMoveSpeed;
}

但是我一直在设置此错误时遇到此错误:

SerializationException: Type UnityEngine.GameObject is not marked as Serializable.

我究竟做错了什么?

3 个答案:

答案 0 :(得分:9)

经过几个小时的实验,我得出结论,Unity 无法序列化GameObject BinaryFormatter。 Unity声称可以在他们的API文档中使用它,但它不是

如果你想删除错误而不删除_weapon GameObject,你应该替换...

[SerializeField]
private GameObject _weapon;

[NonSerialized]
private GameObject _weapon;

这会让你的其余代码运行而不会抛出异常,但你不能反序列化_weapon GameObject。您可以反序列化其他字段。

您可以将GameObject序列化为 xml 。这可以毫无问题地序列化GameObject。它以人类可读的格式保存数据。如果您关心安全性或者不希望玩家在自己的设备上修改分数,您可以encrypt将其转换为binaryBase-64格式之前<强>保存它到磁盘。

using UnityEngine;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System;
using System.Runtime.Serialization;
using System.Xml.Linq;
using System.Text;

public class Player_Manager : MonoBehaviour
{

    // The weapon the player has.
    public GameObject MainHandWeapon;

    void Start()
    {
        Save();
    }

    public void Save()
    {
        float test = 50;

        Debug.Log(Application.persistentDataPath);

        // Stream the file with a File Stream. (Note that File.Create() 'Creates' or 'Overwrites' a file.)
        FileStream file = File.Create(Application.persistentDataPath + "/PlayerData.dat");
        // Create a new Player_Data.
        Player_Data data = new Player_Data();
        //Save the data.
        data.weapon = MainHandWeapon;
        data.baseDamage = test;
        data.baseHealth = test;
        data.currentHealth = test;
        data.baseMana = test;
        data.currentMana = test;
        data.baseMoveSpeed = test;

        //Serialize to xml
        DataContractSerializer bf = new DataContractSerializer(data.GetType());
        MemoryStream streamer = new MemoryStream();

        //Serialize the file
        bf.WriteObject(streamer, data);
        streamer.Seek(0, SeekOrigin.Begin);

        //Save to disk
        file.Write(streamer.GetBuffer(), 0, streamer.GetBuffer().Length);

        // Close the file to prevent any corruptions
        file.Close();

        string result = XElement.Parse(Encoding.ASCII.GetString(streamer.GetBuffer()).Replace("\0", "")).ToString();
        Debug.Log("Serialized Result: " + result);

    }
}


[DataContract]
class Player_Data
{
    [DataMember]
    private GameObject _weapon;

    public GameObject weapon
    {
        get { return _weapon; }
        set { _weapon = value; }
    }

    [DataMember]
    public float baseDamage;
    [DataMember]
    public float baseHealth;
    [DataMember]
    public float currentHealth;
    [DataMember]
    public float baseMana;
    [DataMember]
    public float currentMana;
    [DataMember]
    public float baseMoveSpeed;
}

答案 1 :(得分:3)

Unity不允许你这样做,因为Gameobject包含附加到它的所有脚本。例如网格渲染器,碰撞器等。

如果你想序列化Tranform,你可以通过制作一个新的Vector3位置,Vector3比例,Vector4四元数并将其序列化,然后在反序列化中将这些数据提供给一个新的Transform(例如)来解决这个问题。

但是,尝试序列化与网格渲染器关联的实际网格数据将证明是非常复杂的任务。更好的方法可能只是序列化一个int或代表网格ID的东西,然后在加载时将其转换为正确的引用。

答案 2 :(得分:1)

理想情况下,您应该拥有一个持有武器数据的对象(攻击,持久性等等)并序列化此对象,它会使您的保存游戏更小,并且更多OOP,因为您可以继承该类。

相关问题