estado del juego de guardar / cargar?

12

cuál es el método o algoritmo más utilizado para guardar el estado del juego (perfiles), archivos de texto de bases de datos, cómo funciona el cifrado y cosas relacionadas.

He visto a César IV usar mySQL.

alguna sugerencia.

NativeCoder
fuente

Respuestas:

20

Estoy bastante seguro de que con mayor frecuencia se realiza en un formato propietario (binario), simplemente escribiendo cada variable de cualquier estructura de estado del juego que use en un archivo, o leyendo ese archivo nuevamente en una instancia de la estructura. En C ++, por ejemplo, puede tratar un objeto como una matriz de bytes y simplemente fwrite () en un archivo, o fread () desde el archivo y devolverlo a su forma de objeto.

Si está utilizando Java u otro idioma, puede optar por utilizar la serialización para hacer la tarea realmente fácil. La explicación de Java está al final de esta respuesta; otros lenguajes (de nivel superior a C ++) seguramente también tienen sus propias bibliotecas de serialización o funciones integradas, que debe optar por usar. No importa cuán ineficiente pueda ser la rutina de serialización, el espacio en el disco duro hoy en día es barato, especialmente cuando el estado del juego no debería ser muy grande, y le impide escribir y mantener sus propias rutinas de serialización.

A pesar de todo debe no usar MySQL (acaba de leer la primera frase de esta revisión ). Si realmente necesita una base de datos relacional por alguna razón, use SQLite ; Es un sistema de base de datos ligero y existe en un único archivo de base de datos. Pero para la mayoría de los juegos, las bases de datos relacionales no son el camino a seguir, y las compañías que intentan usarlas generalmente terminan usándolas como una tabla de búsqueda de valor clave en lugar de una verdadera base de datos relacional.

Cualquier tipo de cifrado de archivos de disco local es solo ofuscación ; cualquier hacker solo rastreará los datos justo después de que su programa los descifre. Personalmente estoy en contra de ese tipo de cosas, ESPECIALMENTE con juegos de un jugador. Mi opinión es que los propietarios del juego (clientes que pagan, claro está) deberían poder piratear el juego si así lo desean. En algunos casos, puede crear un mayor sentido de comunidad, y se pueden desarrollar "mods" para su juego que atraigan a más clientes hacia usted. El ejemplo más reciente que viene a la mente es el mod Portal en Minecraft que se lanzó recientemente. Está publicado en sitios de noticias de jugadores en todo Internet, y puedes apostar que aumentó las ventas de Minecraft.


Si por alguna razón estás lo suficientemente loco como para usar Java para el desarrollo de juegos como yo, he aquí una explicación rápida de la serialización en Java:

Mantenga todos sus datos de estado del juego en una clase, haga que la clase sea serializable mediante la implementación Serializable, use la transientpalabra clave si combina variables instanciadas especiales en la clase (los objetos transitorios no se serializan), y simplemente use ObjectOutputStreampara escribir en el archivo y ObjectInputStreamleer desde el archivo . Eso es.

Ricket
fuente
2
Jeje, The Witcher no cifró sus datos. Muy fácil abrir el archivo de guardar juego en un editor hexadecimal, jugar un poco con él y obtener todas las tarjetas de chicas desnudas ... ¡Dios mío, lo siento mucho!
Anthony
He usado la serialización binaria .NET para guardar juegos, y C # es quizás una plataforma un poco más razonable que Java para desarrollar juegos. Me gusta cómo guarda automáticamente un gráfico de objeto completo automáticamente. Esto solía ser mucho más difícil. Por supuesto, ahora existe el desafío de excluir piezas innecesarias como las texturas, pero eso no es un gran problema para lograr.
BlueMonkMN
No estoy en desacuerdo con que C # sea un poco más popular que Java para desarrollar juegos. Más razonable implica cierta subjetividad, y como desarrollador de XNA y Java, prefiero Java. Si lo desea, también puede enumerar instrucciones sobre la serialización en C #, nunca lo he hecho, pero puedo editarlo en mi respuesta. La serialización de Java guarda todo el gráfico de objetos y la palabra clave 'transitoria' en las variables excluye piezas innecesarias como texturas; cualquier miembro no transitorio debe ser serializable o puede escribir un método personalizado writeObject para evitarlo.
Ricket
El pepinillo de Python también guardará un gráfico de objeto completo para usted y es fácil de usar. Cuando llega el momento de deserializar, le devuelven objetos totalmente hidratados, tan fácil como docs.python.org/library/pickle.html
drhayes
Cuando se utiliza el formateador binario incorporado, excluir ciertos campos de la serialización en C # /. NET es tan simple como adornarlos con el atributo [No serializado]. Sin embargo, lo que es fácil pasar por alto es que los eventos generados por el compilador (es decir, cualquier evento sin operadores de agregar / quitar personalizados) crean un campo de respaldo para almacenar sus suscriptores. Por lo tanto, es fácil incluir accidentalmente (y sin saberlo) controladores de eventos en un gráfico de objetos serializados. Para solucionar esto, debe agregar el atributo No serializado a la declaración del evento, pero debe agregar el calificador "field:":[field: NonSerialized]
Mike Strobel
3

Si está escribiendo su propio código, digamos en C ++, puede usar archivos binarios. Los archivos binarios le brindan una forma de cifrado a través de la ofuscación. Pero como se documenta en todas las redes, esa es una forma de seguridad muy débil.

O bien, puede usar algo como RapidXML si desea una solución legible para humanos.

Si está utilizando algún tipo de marco, consulte sus funciones de soporte de archivos. HTH

JustBoo
fuente
0

La mayoría de los juegos que he visto solo usan código escrito a mano para leer / escribir desde archivos binarios. A menudo, el formato en disco será una réplica exacta del diseño de memoria de un objeto, por lo que la carga es solo:

  1. Leer el archivo en la memoria.
  2. Transmitir puntero al búfer al tipo de objeto.

Es rápido, pero es una tarea difícil de mantener, específica de la plataforma e inflexible.

Últimamente, he visto un par de juegos que usan SQLite. A la gente con la que he hablado parece gustarle.

munificente
fuente
0

La serialización se menciona en algunas de las otras respuestas, y estoy de acuerdo en que es una solución razonable. Sin embargo, una forma en que falla es en el versionado.

Digamos que lanzas tu juego y la gente lo juega y crea algunos juegos guardados. Luego, en un parche posterior, desea corregir un error o agregar algunas características. Si utiliza un método de serialización binario simple y agrega un miembro a sus clases, es posible que su serialización no sea compatible con los juegos guardados antiguos cuando los clientes instalan su parche.

Entonces, sea cual sea el enfoque que uses, ¡asegúrate de pensar en este problema antes de lanzar el juego por primera vez! Los clientes no estarán contentos si tienen que comenzar de nuevo después de aplicar un parche.

Una forma de evitar esto es hacer que cada tipo de datos básicos implemente los métodos Guardar (versión) y Cargar (versión) que sean lo suficientemente inteligentes como para saber qué datos guardar y cargar para cada versión del juego. De esa forma, puede admitir la compatibilidad con versiones anteriores de sus juegos guardados y fallar con gracia si un usuario intenta cargar un juego guardado desde una versión más nueva del juego de la que está ejecutando.

kevin42
fuente
1
Como nota rápida: la implementación de las funciones "guardar" y "cargar" para cada versión del juego se convierte rápidamente en una pesadilla de mantenimiento. He encontrado una mejor solución es incrustar un número de versión, escribir funciones "guardar / cargar" para la versión actual del juego y escribir una función de "conversión" de la versión no actual más reciente a la versión actual. Luego, simplemente mantenga todas sus funciones de conversión. Intentar cargar un juego de diez versiones anteriores ejecutaría diez funciones de conversión en serie, luego la función nativa "cargar la versión actual del juego".
ZorbaTHut
Mucho más fácil de mantener a largo plazo: mantener una serie de funciones de "cargar cada archivo de juego anterior" rápidamente se convierte en una operación de tiempo polinómico.
ZorbaTHut
En los juegos en los que he trabajado no es tan complejo: en lugar de mantener varias copias de los métodos de carga / guardado, el único método utiliza el número de versión para determinar qué bytes leer y escribir. Esto se hace aún más fácil si no solo escribe estructuras, sino que implementa la carga y el almacenamiento como operaciones en el nivel de tipo de datos primitivo (por ejemplo, ReadByte / ReadFload / etc). Luego, si agrega un nuevo miembro, puede hacer algo como if (versión> 10) {someNewByte = ReadByte (); } Implementarlo de esta manera también facilita el soporte de diferentes plataformas endian.
kevin42
Otra forma de evitar mejorar el soporte de versiones es evitar que los métodos de serialización / deserialización de sus objetos escriban / lean valores individuales directamente desde una secuencia. En cambio, los objetos podrían escribir sus datos de propiedad en una bolsa de propiedades utilizando pares clave / valor, y luego escribir la bolsa en la secuencia. Durante la deserialización, los objetos podían leer los valores de la bolsa por nombre. Pero en lugar de tener comprobaciones específicas del número de versión como sugiere kevin42, podría tener reglas sobre cómo manejar los valores faltantes (es decir, usar un valor predeterminado estándar cuando el valor requerido no está en la bolsa).
Mike Strobel
0

Si puede usar el mismo formato que usa para almacenar sus niveles, es una ventaja.

Por ejemplo, un juego como Peggle podría tener un diseño de tablero inicial, número de bolas, puntaje actual (0 para el tablero inicial), etc. Luego, un juego guardado puede usar exactamente el mismo formato.

¡Si usa el mismo formato, el juego guardado y la carga de nivel pueden compartir el código, facilitando su trabajo!

Para un juego con archivos de mapa realmente grandes, la partida guardada puede incluir el archivo de mapa por referencia. Los archivos de nivel inicial podrían hacer lo mismo, incluso, lo que hace que volver a ese mapa también sea más fácil si por alguna razón la historia hace que el personaje regrese al mismo lugar, excepto que algunos de los NPC están muertos y hay cadáveres que yacen todos terminado.

Zan Lynx
fuente