Savefiles con XML

El sentido de la progresión en un juego es casi siempre dependiente de un savefile. Esto es un archivo con la información del progreso del jugador. Sea niveles desbloqueados, armas recolectadas, ranking de puntajes o posición del jugador en el mundo, la gran mayoría de los juegos requieren algo así. Esto también es usado para guardar configuraciones como volumen de la música y sonido, resolución preferida, nivel de detalle, dificultad, etc.

En este ejemplo vamos a estar usando la serialización en XML, una serialización con tipado fuerte que nos permite guardar datos de manera rápida y con capacidad retro-compatible.

2017-10-20 13_21_25-C__Users_jrodriguez_Documents_UnityProjects_marauders_dev_Assets_Data_Arena.xml
Así se ve un archivo XML

La ventaja que tiene trabajar con serializaciones es lo fácil que es mappear objetos a texto y viceversa. Otro tipo de serializacion que puede usarse para esto, pero no se cubre en este post es JSON.
.NET ya incluye un serializador y deserializador XML en el framework, por ende, este formato es sumamente cómodo para trabajar con C#. Si les preocupa que un savefile sea fácilmente editable fuera del juego, no hay problema, pueden implementar encriptacion a todo el archivo o a los datos a la hora de guardar.

Manejador IO

Una buena forma de mantener coherencia a la hora de manejar archivos es usar el mismo script para todos los juegos. Esto significa que el código que maneje los archivos tiene que ser 100% genérico. Esta clase la escribí una sola vez en mi vida y desde entonces la he usado para todos mis proyectos, sean juegos o no.

2017-10-20 13_22_11-marauders_dev - Microsoft Visual Studio
FileManagment es una clase estática, no necesita instancia propia ya que su uso es volátil. La primera constante definida es la ubicación raíz de los archivos.

En esta clase vamos a tener las funciones de Crear, Abrir y Guardar archivos.

2017-10-20 13_22_55-marauders_dev - Microsoft Visual Studio
Primero una función básica pero muy necesaria para evitarse tener que crear los archivos a mano. CreateFile se asegura que tanto el directorio como el archivo existan.
2017-10-20 13_22_29-marauders_dev - Microsoft Visual Studio
OpenSaves se encarga de abrir un archivo y deserializar su contenido en el tipo dado T. Hay 2 cosas para notar en esta función. El uso del bloque try catch es porque pueden existir problemas de permisos de lectura y el using es porque de esa manera nos aseguramos de cerrar el file streamer creado.
2017-10-23 13_39_40-marauders_dev - Microsoft Visual Studio
SaveFile se encarga de serializar el objeto de datos y guardar el archivo.

Como se puede apreciar, el manejo de archivos no es complicado, y al usar serializacion, no tenemos que hacer ninguna conversión explicita en los objetos. También nos aseguramos que, si agregamos propiedades a nuestros objetos serializables, los archivos van a poder cargarse igual aunque sean datos de versiones anteriores.

Sets de datos

Los sets de datos vamos a tenerlos en clases definidas por nosotros, la idea de estas clases es que actúen como almacenamiento de datos, no tanto como comportamiento. De manera que estas clases van a tener que implementar el atributo de Serializable y no van a heredar de MonoBehaviour

2017-10-20 13_24_15-marauders_dev - Microsoft Visual Studio
Set de datos de un archivo de Marauders Arena

En el ejemplo de arriba, una instancia especifica de ArenaSave es lo que va a serializarse y guardarse en el archivo. ArenaPlayer es otra clase, que tiene la información de cada perfil que se creó en el juego. Dentro de ArenaPlayer estará la información de cuánto dinero tiene el personaje, que autos desbloqueo, que modificadores tiene cada auto, etc. ArenaSave contiene una colección de ArenaPlayers. Es importante notar que tanto ArenaPlayer como cualquier otra clase que vaya a ser guardada tiene que tener el atributo Serializable, no basta que solo la clase raíz lo tenga.

Consumo de saves

Dentro de ArenaSave podemos definir las funciones para guardar y cargar estos datos.

2017-10-20 13_23_44-marauders_dev - Microsoft Visual Studio
Acá hay un ejemplo de carga de datos, llamamos a la función OpenSaves dándole el tipo de objeto que queremos deserializar y el nombre del archivo. En este momento es el momento ideal para implementar un failsafe si el archivo falla en cargar.

A la hora de guardar un jugador, podemos cargar los datos, actualizar la información de ese jugador (o reemplazarlo completamente) y guardar el archivo.

2017-10-20 13_24_39-marauders_dev - Microsoft Visual Studio
Guardando un perfil de jugador en ArenaSave

En esta función es estática, definida dentro de ArenaSave, y la idea es que reciba una instancia de ArenaPlayer para guardar la información. Pasan varias cosas, lo primero es un checkeo, si no puede cargar el archivo, crea una nueva instancia de ArenaSave así puede seguir con la operación. Luego intenta encontrar el jugador a guardar en los que cargo del archivo, si este no se encuentra, agrega el jugador a la lista, de otra manera actualiza los datos del jugador. Por ultimo guardar el archivo.

Al momento de escribir este post, agregue mas tipos de saves en el Marauders Arena, por ejemplo, uno que guarda toda la configuración de audio, es otro archivo xml y se manipula con la misma clase FileManagement de la misma manera que se manipula el ArenaSave. Es una de esas soluciones que queda vigente de proyecto a proyecto. Si aun no quedo del todo claro, recomiendo volver a leer el post y detenerse luego de cada concepto revisando la primera imagen, el archivo XML.

 

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s