Cómo serializar y guardar un GameObject en Unity

Tengo un juego donde el jugador toma un arma y luego se coloca como la variable GameObject para mi jugador llamado “MainHandWeapon” y estoy tratando de guardar esa arma a través de los cambios de escena, así que estoy tratando de salvarlo. Cómo manejo esto es el siguiente:

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; } 

Pero sigo obteniendo este error de tener esta configuración:

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

¿Qué estoy haciendo exactamente mal?

Después de horas de experimento, llegué a la conclusión de que Unity no puede serializar GameObject con BinaryFormatter . Unity afirma que es posible en su documentación API, pero no es así .

Si desea eliminar el error sin eliminar el _weapon GameObject, debe reemplazar …

 [SerializeField] private GameObject _weapon; 

con

 [NonSerialized] private GameObject _weapon; 

Esto permitirá que el rest de tu código se ejecute sin lanzar una excepción, pero no puedes deserializar _weapon GameObject. Puedes deserializar otros campos.

O

Puedes serializar GameObject como xml . Esto puede serializar GameObject sin ningún problema. Guarda los datos en formato legible para humanos. Si le importa la seguridad o no quiere que los jugadores modifiquen los puntajes en sus propios dispositivos, puede encriptarlos , convertirlos en formato binario o Base-64 antes de guardarlos en el disco.

 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; } 

Unity no te permitirá hacerlo porque un Gameobject forma parte de todos los scripts adjuntos. Por ejemplo, renderizadores de malla, colisionadores, etc.

Si quisieras decir serializar el Tranform, podrías evitar esto haciendo una nueva posición de Vector3, Vector3, Vector4 quaternion y serializar eso en su lugar y luego, al deserializar, alimentar estos datos en una nueva Transformación (por ejemplo).

Pero intentar serializar los datos de malla reales que están asociados con el renderizador de malla sería una tarea bastante compleja. Mejor sería probablemente serializar un int o algo que representa una identificación de malla y luego transmutar esto a la referencia correcta en la carga.

Lo ideal es que tengas un objeto que contenga los datos del arma (ataque, durabilidad, etc.) y serialice este objeto, hace tus juegos de salvar mucho más pequeños y es más OOP, ya que puedes heredar de esa clase.