Como guardar datos con ficheros ini
En el anterior post, como guardar tu juego en Game Maker, hicimos una pequeña introducción sobre lo que hay que tener en cuenta a la hora de guardar datos con Game Maker Studio. Ahora vamos a hablar de unos ficheros con unas características especiales que pueden ser muy útiles para grabar datos.
¿Qué es un fichero ini?
Un fichero con extensión .ini no deja de ser un fichero de texto como cualquier otro. Se puede editar desde el Bloc de notas y no importa mucho su extensión. Antes se utilizaba mucho, por ejemplo, para que arrancase automáticamente un CD, o incluso Windows utilizaba un boot.ini para el arranque. Suele contener información de configuración, ya sea en un programa cualquiera o, en nuestro caso, en un juego hecho en Game Maker.
No es recomendable almacenar grandes cantidades de datos, para eso tendríamos que tratar el fichero de texto como veremos en otro post.
¿Como es la estructura del archivo?
Los ficheros ini tienen una estructura muy particular, un poco parecido a un fichero xml (aunque estos son más versátiles, de ahí que se han dejado de usar a favor de éstos). Para acceder a los datos, todos están dentro de una sección. Dentro de esa sección tendremos las claves y su valor. Por ejemplo:
[Settings] sound_fx = 0 music = 1
Dentro de la sección Settings, tenemos dos claves, sound_fx y music, con valores diferentes. Así que un fichero ini podemos encontrar esto:
[achievement] 7=1.000000 6=1.000000 5=1.000000 [player] score="2391.000000" max_level=45.000000 language=eng time_total=0'27'' [items] 0=4.000000 1=2.000000
No podemos encontrar claves sin su sección, por ejemplo
lives = 3
Pero sí que podemos diferenciar/separar la misma clave en dos secciones diferentes.
[player1] inventory = 25 lives = 2 [player2] inventory = 10 lives = 1
Ya os podéis empezar a imaginar el potencial de esto…
Limitaciones en el uso de ficheros
Como podéis imaginar, podemos estructurar los datos dentro de un fichero para tenerlo todo ordenado. Aunque existe una serie de límites.
Uno de las restricciones comentadas es que no podemos almacenar mucha información. No se donde está el límite, pero si queremos guardar todos los objetos con todas sus propiedades, creo que la lectura de dicho fichero será muy lenta.
Otra restricción es la estructura cerrada que nos ofrece. ¿Podríamos crear una sección dentro de otra sección? No. ¿Podemos ofrecer varios valores a una clave? No. Siempre tiene que ser Sección→clave→valor. Puede parecer un poco limitado, en comparación con los ficheros xml que podemos tener la estructura que queramos.
Con los ficheros ini solo se puede tener un fichero abierto a la vez. Si queremos gestionar varios ficheros, debemos abrir y cerrar cuando sea necesario.
Otro límite en el uso de ficheros, no solo de los ficheros ini, es que no deberíamos leer/ni escribir en un evento Step y Draw
. Aunque la lectura nos parezca rápida, hacer esto 30 veces por segundo, que es como está configurado por defecto estos eventos, hará que se ralentice nuestro juego demasiado, aunque no tenga muchos objetos en pantalla.
Funciones para gestionar ficheros ini
Siempre que accedemos a un fichero ini, debemos hacer hacer los siguientes pasos.
- Abrir el fichero
- Leer o escribir en él.
- Comprobaciones.
- Cerrar el fichero.
Estos tres pasos los podemos hacer seguidos, es decir dentro del mismo evento, o podemos dejar el fichero abierto para posibles lecturas/escrituras.
Por ejemplo, tenemos un menú que guardamos si se escucha la música o no. Yo lo que haría es que si cambia ese valor, abriría el fichero, escribiría y lo cerraría.
Pero imaginemos que estamos gestionando los valores de un personaje de rol, y mientras cambiamos su inventario o características, se vaya grabando esos datos. Podemos abrir el fichero al inicio de la room, grabar o leer todas las veces necesarias, y luego cerrar el fichero una vez hemos acabado.
Así que queda en la elección de cada uno cuál es la mejor manera de hacerlo. Ahora vamos con las funciones.
ini_open(fichero)
Con esta función abre un fichero ini, indicando su nombre como parámetro.
ini_close()
Cierra el fichero ini que está abierto. No se le pasa ningún parámetro porque, como hemos dicho, solo puede haber uno abierto. Pero si que devuelve una cadena con todo el valor del fichero ini.
ini_read_real(seccion, clave, valor_defecto) / ini_read_string(seccion, clave, valor_defecto)
Tenemos dos funciones para distinguir entre dos tipos de datos, los números, con decimales, y las cadenas de texto. Los valores booleanos, true o false, hay que tratarlos como números.
Los parámetros son la sección, la clave y un valor por defecto si no encuentra la clave. Es decir, si por algún motivo no hemos creado la clave o el fichero ini no existe, evitaremos un error con ese tercer parámetro. Un ejemplo:
ini_open("savedata.cnf"); music = ini_read_real("config", music, true); name = ini_read_string("player", "name", "David"); ini_close();
ini_write_real(seccion, clave, valor_defecto) / ini_write_string(seccion, clave, valor_defecto)
Con estas funciones guardamos los datos en el fichero ini. Debemos distinguir a la hora de guardar números o texto. Funciona de una manera parecida a la vista:
ini_open("savedata.cnf"); ini_write_string("player", "score", score); ini_close();
Fijaros que la extensión puede ser cualquiera, tampoco es necesaria ponerle.
ini_key_exists(seccion, clave) / ini_section_exists(seccion)
Estas funciones sirven para comprobar si existe una clave o sección. Yo no suelo usarlas porque, al tener la posibilidad de tener un valor por defecto en la clave, no creo necesaria comprobar si están creadas en el fichero. Pero puede ser útil para hacer comprobaciones, como por ejemplo, si hemos guardado los datos correctamente.
ini_key_delete(seccion, clave) / ini_section_delete(seccion)
Con la primera función, eliminamos una clave, y su valor, de un fichero. Con la segunda, eliminamos una sección, y todas las claves con sus valores que pueda tener.
ini_open_from_string(cadena)
Crea un fichero ini temporal, que se elimina una vez se cierra. Aunque no queramos guardar datos en el disco, podemos usar todas las funciones de un fichero ini en nuestro juego. Además, se le puede pasar por parámetro una cadena con una configuración ini. Recordemos que podemos recuperar una cadena con la función ini_close()
, así que podríamos leer un fichero ini y utilizarlo como si fuese un fichero temporal (escribir en él), sin que se vea afectado el fichero origen. Por ejemplo.
ini_open(“savedata,cnf”); str = ini_close(); ini_open_from_string(str); ini_write_string(“player”,”score”,score);
Con el código de arriba, no se quedaría grabado la puntuación en el fichero ini, pero se podría gestionar su lectura y escritura como si lo fuese. Recordemos que falta ini_close()
para cerrar el fichero temporal.
Puede ser muy útil para hacer simulaciones o demos. Se me ocurre que podemos tener un juego que tengas la posibilidad de entrenarte en una pantalla y saber todo lo logrado sin que quede grabado en ningún sitio.
Para que uso yo los ficheros ini
Suelo usar ficheros ini en los juegos que hago. Lo uso para guardar configuraciones, como por ejemplo el idioma elegido, si quieres escuchar música o efectos de sonido, hasta que nivel o room ha llegado el jugador, etc. También los utilizo para guardar estadísticas: puntuación global conseguida, récords como mejor tiempo o número de enemigos abatidos, o para saber los logros desbloqueados (y sincronizarlos luego con Game Center o Google Play Games). También puede servir para guardar inventario o progreso del personaje (nivel de experiencia, monedas, etc.)
Entonces, ¿cómo podríamos grabar las partidas enteras? Pues habría que recorrer los objetos que nos interese, y saber que variables son las que nos interesa (posición x/y, variables creadas), además de las variables globales. Debemos conocer el nombre de las variables para poderlas asociar. Puede parecer un poco rudimentario, pero es la mejor manera de controlar lo que graba. ¡Aunque hay que vigilar que no se olvide nada!
Espero que haya sido útil este post y haya resuelto las posibles dudas para poder grabar vuestros juegos. Recordad que siempre espero vuestra opinión en los comentarios.
Excelente post, muchas gracias por tus aportes, me has salvado en mas de una ocasión.
Sería muy interesante y util que crearas un post de como colgar nuestro juego a la tienda y realizar ventas, asi como poner la publicidad necesaria y el método de pago. Pienso que con un post de ese tipo quedaría una guía bastante completa y profesional.
Saludos.
¡Hola!
La verdad es que eso entra en la parte de marketing, y es un mundo lo bastante extenso como para tener sección propia.
Habría que montar tu propia página web, redes sociales, vídeos, kit de prensa, enviar mails a sitios para que vean la demo y opinen, etc… ¡Mucho trabajo por delante!
Como respuesta rápida, puedes probar en itch.io, que te permite publicar y vender tu juego.
¡Pruébalo y me lo comentas!
Tengu una duda, si creo un archivo ini o cualquier tipo de archivo manualmente, cómo lo leo? Es decir, tengo lo siguente:
var file = “datafiles\messages.ini”;
show_message(file+”::”+string(file_exists(file)));
Y por mas que cambio la variable file, usando las constantes working_directory, temp_directory, program_directory, siempre da falso, como si el archivo no existiera, pero sí existe.
Yo no utilizo ninguna constante de directory.
Si creas un fichero fijo, como mensajes o texto de traducción, lo incluyo en “Included Files”. Luego lo llamo así:
ini_open("messages.ini");
Si es un fichero que creo en el juego, para guardar puntuación, variables y demás, lo hago de la misma manera.
El problema viene cuando grabas un fichero que está en “Included Files”, porque lo tendrás duplicado en el sistema (dónde se instala/ejecuta el juego y dónde se guardan los datos). Game Maker buscará siempre en la carpeta dónde se guardan los datos e ignorará el fichero que hay dónde se ejecuta el juego (a no ser que se borre). Por eso hay que separar que nos interesa guardar y leer.
Espero haber resuelto la duda.
Saludos excelente post, acabo de descubrir el sitio y suscribirme ya que me interesa entrar en este mundo de los videojuego, una pregunta ¿se puede usar el .ini para guardar el highscore de un juego para dispositivos móviles (Android e iOS)?
Buenas Jorgen,
los ficheros ini funcionan perfectamente para dispositivos móviles. Yo lo uso y funciona, aunque nunca he descubierto dónde gguarda el fichero.
El otro día hice una prueba con una exportación a HTML5 y también leía un .ini incluido en el proyecto!
David
Gracias David por la respuesta probaré a ver como me va 😀
Muy bueno! podrías hacer un tutorial para guardar la información en la nube, si el usuario borra el juego y luego lo vuelve a bajar y se loguea (mediante cualquier metodo) lo recupera.
Lo tengo pendiente ;). Estoy buscando la mejor manera, ya que existen varias formas de hacerlo. La forma gratuita es saber programar en páginas web, por ejemplo PHP, y montarte un WebService, pero no me gusta por el mantenimiento, más los problemas que puedes tener (caídas de servidor, hackeos, etC).
La otra opción sería buscar una web que te ofrezca ese servicio. en un post de Game Maker habla del tema, he visto precios y son asequibles, aunque el ejemplo diría que es sólo para leer datos y no grabar.
Lo dicho, es una cosa que tengo en la cabeza, pero quiero hacerla que se entienda muy bien, y que sea fácil (lo malo es que no es gratis) para todo el mundo.
Pero si es muy complejo podes subir la extension en la tienda a 1 U$s, es un tema interesante y creo que como yo hay muchos que están con el mismo problema.
hola, muy buen post. please help..jaja tengo problemas trabajando con working directory. ojala y puedas ayudarme. necesito que lea si existe un fichero y si no existe lo cree. pero no me hace caso Y.Y.. Ejmp:
if not directory_exists(working_directory+”\\”+string(current_month))
{
directory_create(working_directory+”\\”+string(current_month))
{
if not file_exists((working_directory+”\\”+string(current_month+”\\”+date_date_string(global.dia)+”.ini”)))
{
ini_open((working_directory+”\\”+string(current_month+”\\”+date_date_string(global.dia)+”.ini”)))
{
}}}}
he sustituido working_directory por una dirección ejmp: c: \\etc\\etc y nada, he sustiduido el_ini open por drirectory_create(c:\\etc\\etc\\+date_date_string(global.dia)+”ini”y nada. estoy al cambiar de hobit por pegarle a la pared creo que resultara mas gratificante…
No puedes usar direcciones absolutas tipo “C:\”, porque desde Game Maker no hay acceso. Yo no suelo poner nunca la variable working_directory, porque siempre trabajo en el sandbox. pondria directamente
if not directory_exists (string(current_month)) …
Si usas una ruta, tammpoco hace falta poner “\\” dos barras, con una te lo coge bienn.
Mira aquí que hablo sobre el tema
https://www.aprendegamemaker.com/como-guardar-juego-game-maker/
Hola amigo! Excelente información, soy nuevo en game maker, una consulta, es posible guardar el progreso de diferentes jugadores? Que guarde su ID y su progreso en el mismo juego.
Claro, yo lo que haría es grabar cada seccion con la ID del jugador y luego dentro todos los valores y progreso que necesitas.
Hey!
Soy Ylber, Tengo 14 Años y Soy Desarrollador de Videojuegos con *Game Maker Studio*. En la Mayoria de los Juegos Comunes se Utiliza Los Guardados de Partida (Archivos INI). Pero Ya Que Al Usar Estos Sistemas en *Game Maker Studio*, Los Archivo se Crean en *%APPDATA%* o Algún Otro Lado (Lugar de Ejecución). Y Eso Me Intriga un Poco Ya Que Es Muy Facil ”Hackear” O Alterar un Archivo De Estos. Entonces, Mi Pregunta es:
Existe Alguna Manera o Posibilidad de ‘Blockear’ Los Archivos Creados Dentro del Juego en GMS. (Los Archivo .INI)??.
GRACIAS!!
He visto tu página web y me ha gustado bastante. ¡Continúa así haciendo tus juegos!
Diría que ahora con Game Maker podrías guardar el fichero en cualquier lugar del ordenador, pero no te lo recomiendo. La mejor opción que tienes es encriptar los resultados que guardas en el fichero ini, así no lo pueden cambiar.
Mira en esta web que tiene varios scripts para hacerlo. A mi me gusta el Rc4, ya que puedes poner una clave que sin ella no pueden conseguir descifrarlo.
GMLScripts