Estoy creando un editor de niveles para un juego que puede editar niveles en el modo de edición de Unity. Guarda el progreso al final, que se puede volver a cargar cuando el juego se está ejecutando, pero resulta que no puede serializar el Gameobject de Unity ni ningún objeto C# personalizado de Unity (incluso si lo dice). Pude serializar la mayoría de las cosas, pero me quedé con un objeto Dictionary.
Ahora aquí está el problema.
[HideInInspector] public Dictionary<GameObject, Vector2> occupants;
Esto contiene un diccionario de un GameObject y un Vector2 (el Vector 2 es la posición en la cuadrícula 2d y no en el espacio 2d). Nada de esto es serializable por el método normal.
public static void SaveDataValues(DataValuesToSave dataValues, string level) { BinaryFormatter formatter = new BinaryFormatter(); string path = Application.persistentDataPath + level + ".dat"; FileStream stream = new FileStream(path, FileMode.Create); DataValuesToSave data = dataValues; formatter.Serialize(stream, data); stream.Close(); }¿Cómo puedo serializar este Diccionario? Cualquier sugerencia sera apreciada.
En general: ¡No deberías usar nunca más BinaryFormatter !
Puede crear una clase contenedora que implemente la interfaz ISerializationCallbackReceiver . ¡En su ejemplo, incluso hay casi su caso de uso exacto!
Una solución ligeramente modificada podría verse como, por ejemplo
[Serializable] public class YourDictionary: Dictionary<GameObject, Vector2>, ISerializationCallbackReceiver { [HideInInspector][SerializeField] private List<GameObject> _keys = new List<GameObject>(); [HideInInspector][SerializeField] private List<Vector2> _values = new List<Vector2>(); public void OnBeforeSerialize() { _keys.Clear(); _values.Clear(); foreach (var kvp in this) { _keys.Add(kvp.Key); _values.Add(kvp.Value); } } public void OnAfterDeserialize() { Clear(); for (var i = 0; i != Math.Min(_keys.Count, _values.Count); i++) { Add(_keys[i], _values[i]); } } }de esta manera, mantiene toda la funcionalidad del diccionario y sus interfaces, pero simplemente agrega la serialización encima.
y luego en tus otros scripts usas
[HideInInspector] public YourDictionary occupants; y utilícelo como un Dictionary<GameObject, Vector2> (me refiero a Add , Remove , Clear , foreach , etc.).
Y aquí está en acción. Acabo de usar este script de prueba simple
public class NewBehaviourScript : MonoBehaviour { public GameObject obj; [HideInInspector] public YourDictionary occupants; [ContextMenu(nameof(Add))] private void Add() { Vector2 vec = obj.transform.position; occupants.Add(obj, vec); } [ContextMenu(nameof(Apply))] private void Apply() { foreach (var kvp in occupants) { kvp.Key.transform.position = kvp.Value; } } [ContextMenu(nameof(Remove))] private void Remove() { occupants.Remove(obj); } }y ahora felizmente puede almacenar, eliminar y aplicar posiciones para objetos en la escena;)