Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Guardar partidas.

Iniciado por Goosebrush, 03 de Septiembre de 2012, 03:47:21 PM

« anterior - próximo »

Goosebrush

Hola a todos !!

Quiero meter en mi juego la opción de guardar y cargar partidas (el juego es para PC, no para XBOX360) y no tengo ni idea de cómo gestionar lo de guardar ciertos datos en un fichero y luego poder leerlos para cargar la situación del personaje.

¿Alguien sabe cómo hacerlo o tiene algún enlace con algún ejemplo?

Gracias !!

[EX3]

Exactamente que preguntas? El como guardar los datos en un archivo y despues cargarlos o el como gestionar esos datos en tu juego (como organizar y escribir los estados de los objetos de la escena y despues poder cargarlos desde disco, etc...)?

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Goosebrush

El guardar datos en un archivo y luego cargarlos. Ahí es donde ando un poco perdido.  ^_^'

[EX3]

Siendo .NET podrias jugar con la serializacion a XML de las clases que te brinda una opcion rapida tanto de exportar los datos a un archivo XML y de realizar la importacion de la misma manera :)

Te paso el codigo de las funciones que uso en mis proyectos para serializar y deserializar objetos en XML:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace TuProyecto
{
    /// <summary>
    /// Serializacion XML.
    /// </summary>
    public static class Serializers
    {
        /// <summary>
        /// Serializa un objeto a un archivo XML.
        /// </summary>
        /// <param name="data">Objeto a serializar a XML.</param>
        /// <param name="filename">Archivo XML a generar.</param>
        public static void SerializeToFile(object data, string filename)
        {
            XmlSerializer mySerializer = new XmlSerializer(data.GetType());
            StreamWriter myWriter = new StreamWriter(filename);
            mySerializer.Serialize(myWriter, data);
            myWriter.Close();
        }

        /// <summary>
        /// Deserializa un archivo XML a objeto.
        /// </summary>
        /// <typeparam name="T">Tipo del objeto a deserializar.</typeparam>
        /// <param name="filename">Archivo XML a deserializar.</param>
        /// <returns>Devuelve el contenido del XML en el formato indicado.</returns>
        /// <remarks>Esta funcion permite deserializar un archivo XML desde cualquier ubicacion salvo el Content Manager.</remarks>
        public static T DeserializeFromFile<T>(string filename)
        {
            XmlSerializer mySerializer = new XmlSerializer(typeof(T));
            FileStream myFileStream = new FileStream(filename, FileMode.Open);
            T ret = (T)mySerializer.Deserialize(myFileStream);
            myFileStream.Close();
            return ret;
        }
    }
}


Las funciones son genericas, permiten serializar cualquier tipo de clase, sea la que sea. Su uso es muy sencillo:
// Exportar una clase a un archivo XML:
SerializeToFile(objetoASerializar, "nombrearchivo.xml");

Aqui, todos los campos y estructuras publicas que tenga definida la clase se exportaran en formato XML en el archivo que definas.

// Importar datos del archivo:
miClase instanciaClase;

instanciaClase = DeserializeFromFile<miClase>("nombrearchivo.xml");

Aqui instanciaClase se creara con el contenido de la estructura XML que contiene el archivo que indiques (siempre y cuando la estructura coincida con la de miClase, si realizas cambios en miClase te dara error obviamente).

Un detalle, el unico inconveniente de los serializadores es que no pueden trabajar con objectos Dictionary, pero tranquilo, un MVP se curro una clase basada en Dictionary que si se puede serializar, aqui esta el codigo:
/// Codigo basado en el original de John Saunders de su articulo "One Way to Serialize Dictionaries"
/// http://johnwsaundersiii.spaces.live.com/blog/cns!600A2BE4A82EA0A6!699.entry

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.Serialization;

namespace TuProyecto
{
    /// <summary>
    /// Clase Diccionario que soporta serializacion a XML.
    /// </summary>
    /// <typeparam name="K">Tipo de dato de la clave.</typeparam>
    /// <typeparam name="V">Tipo de dato del valor.</typeparam>
    /// <remarks>Los serializadores XML de .NET (el InmediateXMLSerializer de XNA no se ve afectado) no puede serializar clases que implementen la interfaz IDictionary. Esta clase implementa las funcionalidades de un diccionario (IDictionary) pero con capacidad para ser serializado a XML.</remarks>
    public class SerializableDictionary<K, V>
    {
        #region Construction and Initialization
        /// <summary>
        /// Constructor de la clase.
        /// </summary>
        /// <param name="original">Diccionario (IDictionary) que se usara para inicializar la clase.</param>
        public SerializableDictionary(IDictionary<K, V> original)
        {
            this.Dictionary = original;
        }

        /// <summary>
        /// Constructor de la clase.
        /// </summary>
        public SerializableDictionary()
        {
            this.Dictionary = new Dictionary<K,V>();
        }
        #endregion

        #region Interfaz similar a IDictionary
        /// <summary>
        /// Añade un elemento al diccionario.
        /// </summary>
        /// <param name="Key">Clave del elemento.</param>
        /// <param name="Value">Valor del elemento.</param>
        public void Add(K Key, V Value)
        {
            this.Dictionary.Add(Key, Value);
        }

        /// <summary>
        /// Añade un elemento al diccionario.
        /// </summary>
        /// <param name="item">Elemento a añadir.</param>
        public void Add(SerializableKeyValuePair item)
        {
            this.Dictionary.Add(item.ToKeyValuePair());
        }

        /// <summary>
        /// Elimina un elemento del diccionario.
        /// </summary>
        /// <param name="Key">Clave del elemento.</param>
        public void Remove(K Key)
        {
            this.Dictionary.Remove(Key);
        }

        /// <summary>
        /// Elimina un elemento del diccionario.
        /// </summary>
        /// <param name="item">Elemento a eliminar.</param>
        public void Remove(SerializableKeyValuePair item)
        {
            this.Dictionary.Remove(item.ToKeyValuePair());
        }

        /// <summary>
        /// Devuelve la lista de valores del diccionario.
        /// </summary>
        [XmlIgnore]
        public ReadOnlyCollection<V> Values { get { RebuildInternalDictionary(); return this.Dictionary.Values.ToList<V>().AsReadOnly(); } }
        //public ICollection<V> Values { get { RebuildInternalDictionary(); return this.Dictionary.Values; } }

        /// <summary>
        /// Devuelve la lista de claves del diccionario.
        /// </summary>
        [XmlIgnore]
        public ReadOnlyCollection<K> Keys { get { RebuildInternalDictionary(); return this.Dictionary.Keys.ToList<K>().AsReadOnly(); } }
        //public ICollection<K> Keys { get { RebuildInternalDictionary(); return this.Dictionary.Keys; } }

        /// <summary>
        /// Propiedad por defecto del diccionario.
        /// </summary>
        /// <param name="key">Clave del elemento.</param>
        /// <returns>Devuelve el elemento del diccionario con la clave indicada.</returns>
        /// <remarks>Esta propiedad permite acceder directamente a la lista de elementos pasando como parametro la clave, de igual forma a como se haria con un Dictionary(IDictionary).</remarks>
        [XmlIgnore]
        public V this[K key] { get { RebuildInternalDictionary(); return this.Dictionary[key]; } }

        /// <summary>
        /// Numero de elementos del diccionario.
        /// </summary>
        [XmlIgnore]
        public int Count { get { RebuildInternalDictionary(); return this.Dictionary.Count; } }
        #endregion

        /// <summary>
        /// Reconstruye el diccionario interno si la lista tiene datos.
        /// </summary>
        /// <remarks>Este metodo se implementa para los casos en que la instancia de la clase ha sido generada a
        /// partir de deseriaizacion ya que el diccionario interno no se reconstruye automaticamente.</remarks>
        private void RebuildInternalDictionary()
        {
            if (this.Dictionary.Count == 0 && this._list != null && this._list.Count > 0)
            {
                foreach (SerializableKeyValuePair kvp in this._list)
                    this.Dictionary.Add(kvp.ToKeyValuePair());
            }
        }

        #region The Proxy List
    /// <summary>
    /// Acceso al diccionario (IDictionary) interno.
    /// </summary>
    [XmlIgnore]
    public IDictionary<K, V> Dictionary { get; internal set; }

    /// <summary>
    /// Holds the keys and values
    /// </summary>
    public class SerializableKeyValuePair
    {
        public K Key { get; set; }
        public V Value { get; set; }
        /// <summary>
        /// Convertir clase a KeyValuePair.
        /// </summary>
        /// <returns>Devuelve una instancia de KeyValuePair para ser usada con el diccionario (IDictionary) interno de la clase.</returns>
        internal KeyValuePair<K, V> ToKeyValuePair()
        {
            return new KeyValuePair<K, V>(this.Key, this.Value);
        }
    }

    // This field will store the deserialized list
    private Collection<SerializableKeyValuePair> _list;

   

    /// <remarks>
    /// XmlElementAttribute is used to prevent extra nesting level. It's
    /// not necessary.
    /// </remarks>
    [XmlElement]
    public Collection<SerializableKeyValuePair> KeysAndValues
    {
        get
        {
            if (_list == null)
            {
                _list = new Collection<SerializableKeyValuePair>();
            }

            // On deserialization, Original will be null, just return what we have
            if (Dictionary == null)
            {
                return _list;
            }

            // If Original was present, add each of its elements to the list
            if (this.Dictionary.Count > 0) _list.Clear();
            foreach (var pair in Dictionary)
            {
                _list.Add(new SerializableKeyValuePair { Key = pair.Key, Value = pair.Value });
            }

            return _list;
        }
    }
    #endregion

        /// <summary>
        /// Convenience method to return a dictionary from this proxy instance
        /// </summary>
        /// <returns></returns>
        public Dictionary<K, V> ToDictionary()
        {
            return KeysAndValues.ToDictionary(key => key.Key, value => value.Value);
        }
    }
}


Con esto ya tienes material para exportar e importar datos de los objetos de tu juego a disco :) El resto ya es como tu te organices los datos.

Espero te sirva de ayuda ;)

Salu2...

P.D.: Ojo, los serializadores no trabajan el mismo formato XML que controla el Content de XNA. Esto te sirve si vas a guardar y leer archivos mediante System.IO como en cualquier otra aplicacion de .NET. De todos modos, en tiempo de ejucion no podrias guardar tampoco datos en el Content.
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Goosebrush

Muchísimas gracias !!!

No tengo mucha idea de XML pero repasare todo el código y si tengo alguna duda te pregunto.

Gracias de nuevo.  ;)

[EX3]

Tranquilo, con esto no vas a necesitar mucha idea de XML, ya se encarga el serializador de ello por ti, esa es la gracia ;)

Salu2..
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

bnl

Tambien se puede serializar a binario para evitar que los usuarios puedan leer y modificar con facilidad el contenido del fichero y hacer "trampas"
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

Goosebrush

Cita de: bnl en 06 de Septiembre de 2012, 08:01:53 AM
Tambien se puede serializar a binario para evitar que los usuarios puedan leer y modificar con facilidad el contenido del fichero y hacer "trampas"


Gracias por el consejo. A ver si este fin de semana me pongo y consigo montar un sistema de guardado decente. Aunque no me desagrada dejar el juego como esta y tener que pasárselo de un tirón (como en los viejos tiempos en los recreativos :P). Pero hoy en día el tiempo apremia y no todo el mundo puede dedicar 4 horas seguida de vicio.  ;)

[EX3]

A raiz de este post me he animado para escribir una entrada en mi blog juntando todo lo que conozco del tema, con codigo para XBox360 y Windows Phone incluido, viene tambien el codigo para realizar la serializacion a binario que comenta blau :)

Visual Studio EX3 - Serialización de datos en .NET: como exportar e importar datos de nuestro juego en archivos fácilmente

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Goosebrush

Muchas gracias !! Esto si es dar las cosas bien mascadas, ya solo falta que te pase el codigo y me lo implementes tu.  :D

Ya os informo como me queda el tema.  ;)

Goosebrush

Pues ya esta implementado y funcionando. Muchas gracias por todo !!!






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.