sql >> Base de Datos >  >> RDS >> Database

Diseño de bases de datos y juegos MMO

Seamos honestos:a todos nos encanta jugar, especialmente en nuestras computadoras. Hasta que Internet se generalizó, la mayoría de nosotros jugábamos juegos de computadora solos, generalmente contra oponentes de IA. Fue divertido, pero tan pronto como te diste cuenta de cómo funcionaba la mecánica del juego, el juego perdió la mayor parte de su magia.

El desarrollo de Internet movió los juegos en línea. Ahora, podemos jugar contra oponentes humanos y probar nuestras habilidades contra las de ellos. ¡No más juegos de memoria!

Entonces surgieron los juegos masivos multijugador en línea (MMO) y lo cambiaron todo. Miles de jugadores se encontraron en los mismos universos de juego, compitiendo por los recursos, negociando, comerciando y peleando. Para hacer posibles estos juegos, se necesitaba una estructura de base de datos que pudiera almacenar toda la información relevante.

En este artículo, diseñaremos un modelo que incorpore los elementos más comunes que se encuentran en los juegos MMO. Discutiremos cómo usarlo, sus limitaciones y sus posibles mejoras.

Introducción a los modelos de datos para juegos MMO

Hay muchos juegos MMO muy populares hoy en día, e involucran todo tipo de escenarios. Me centraré aquí en juegos de estrategia como Ogame , Travian , Esparta :Guerra de imperios y Imperia en línea . Estos juegos tienen más que ver con la planificación, la construcción y la elaboración de estrategias, y menos con la acción directa.

Los juegos MMO están ambientados en diferentes universos, son visualmente diferentes y usan opciones de juego más o menos diferentes. Aún así, algunas ideas son las mismas. Los jugadores compiten por ubicaciones, luchan por ellas y forman alianzas con (y contra) otros jugadores. Construyen estructuras, recolectan recursos e investigan tecnologías. Construyen unidades (como guerreros, tanques, comerciantes, etc.) y las usan para comerciar con aliados o luchar con oponentes. Todo eso debe estar respaldado en nuestra base de datos.

Podemos pensar en estos juegos como juegos de mesa en línea con muchas casillas indexadas. Cada cuadrado puede tener muchas acciones diferentes asociadas con él; algunas acciones incluirán múltiples cuadrados, p. cuando movemos unidades o recursos de un lugar a otro.




La base de datos se divide en cinco áreas principales:

  • Players / Users
  • Alliances
  • Locations and Structures
  • Research and Resources
  • Units

Las siete tablas no agrupadas restantes están relacionadas con las unidades y describen la posición de las unidades y los movimientos en el juego. Veremos cada una de estas áreas con mucho más detalle, comenzando con Jugadores y Alianzas .

Jugadores y Alianzas

Sin duda, los jugadores son la parte más importante de cualquier juego.

El player La tabla contiene una lista de todos los jugadores registrados que participan en una instancia de juego. Almacenaremos los nombres de usuario, las contraseñas y los nombres de pantalla de los jugadores. Estos se almacenarán en el user_name , password y nickname atributos respectivamente.

Los nuevos usuarios deberán proporcionar una dirección de correo electrónico durante el registro. Se generará un código de confirmación y se les enviará, al que responderán. Actualizaremos la confirmation_date atributo cuando el usuario verifica su dirección de correo electrónico. Entonces, esta tabla tiene tres claves únicas:user_name , nickname y email .

Cada vez que un usuario inicia sesión, se agrega un nuevo registro en el login_history mesa. Todos los atributos de esta tabla se explican por sí mismos. El logout_time es específico. Puede ser NULL cuando la sesión actual del usuario está activa o cuando los usuarios abandonan el juego (sin cerrar sesión) debido a problemas técnicos. En el login_data atributo, almacenaremos detalles de inicio de sesión como la ubicación geográfica de un jugador, la dirección IP y el dispositivo y el navegador que utilizan.

La mayoría de los juegos MMO nos permiten cooperar con otros jugadores. Una de las formas estándar de cooperación entre jugadores es la alianza. Los jugadores comparten sus "datos privados" en el juego (estado en línea, planes, ubicación de sus ciudades y colonias, etc.) con otros para beneficiarse de las acciones aliadas y por pura diversión.

La alliance tabla almacena información básica sobre alianzas de juego. Cada uno tiene un alliance_name único que almacenaremos. También tendremos un campo, date_founded , que almacena cuando se fundó la alianza. Si se disuelve una alianza, almacenaremos esa información en el date_disbanded atributo.

El alliance_member tabla relaciona jugadores con alianzas. Los jugadores pueden unirse y abandonar la misma alianza más de una vez. Debido a esto, el player_idalliance_id par no es una clave única. Mantendremos información sobre cuándo un jugador se une a la alianza y cuándo (si) se va en el date_from y date_to los campos. El membership_type_id atributo es una referencia al membership_type diccionario; almacena el nivel actual de derechos de los jugadores en la alianza.

Los derechos de los jugadores en una alianza pueden cambiar con el tiempo. Las membership_actions , membership_type y actions_allowed juntas definen todos los derechos posibles para los miembros de la alianza. Este modelo no permite a los jugadores definir sus propios niveles de derechos en una alianza, pero eso podría lograrse fácilmente agregando nuevos registros en el membership_type diccionario y almacenar información sobre las alianzas con las que están relacionados.

En resumen:los valores almacenados en estas tablas los definimos nosotros durante la configuración inicial; cambiarán solo si introducimos nuevas opciones.

El membership_history table almacena todos los datos relacionados con los roles o derechos de los jugadores dentro de una alianza, incluido el rango cuando estos derechos eran válidos. (Por ejemplo, podría tener permisos de "principiante" durante un mes y luego "membresía completa" a partir de ese momento). El date_to el atributo es NULLable porque los derechos actualmente activos aún no han terminado.

Las membership_actions El diccionario contiene una lista de todas las acciones que los jugadores pueden realizar en una alianza. Cada acción tiene su propio action_name y la lógica del juego se basa en estos nombres. Podemos esperar valores como “ver lista de miembros” , “ver los estados de los miembros” y “enviar mensaje” aquí.

El membership_type El diccionario contiene los nombres únicos de los grupos de acción utilizados en el juego. Las actions_allowed table asigna acciones a los tipos de membresía. Cada acción se puede asignar a un tipo solo una vez. Por lo tanto, la membership_action - membership_type par forma la clave única para esta tabla.

Ubicaciones y Estructuras

Las ubicaciones de juego son áreas donde los jugadores recolectan recursos y construyen estructuras y unidades. Algunos juegos tienen un rango predefinido de ubicaciones posibles, mientras que otros pueden permitir que los usuarios definan sus propias ubicaciones.

En un espacio 3D, las ubicaciones se pueden definir con coordenadas [x:y:z]. Si un juego tiene un rango predefinido, es posible que no permita a los jugadores usar ninguna ubicación fuera del rango [0:1000] para los tres ejes, por lo que estamos limitados a un espacio de 1000 * 1000 * 1000.

Por otro lado, tal vez queramos permitir que los jugadores ingresen las coordenadas exactas de su nueva ubicación, p. [1001:2073:4] – y queremos que el juego lo procese por ellos.

Mantendremos una lista de todas las ubicaciones utilizadas en una instancia de nuestro juego en la location mesa. Cada ubicación tiene su propio nombre, pero los nombres no son únicos. Por otro lado, las coordinates El atributo debe contener solo valores únicos. Las coordenadas de ubicación se almacenan como valores de texto, por lo que podemos almacenar coordenadas para juegos 3D como [112:72:235]. Las coordenadas para juegos 2D se pueden almacenar como <1102:98>.

En algunos juegos, las ubicaciones tendrán varios cuadrados que se utilizan para albergar estructuras o unidades. Mantendremos esa información en la dimension atributo, que es un campo de texto. Una dimensión puede ser simplemente el número de cuadrados en una cuadrícula 2D o 3D. El player_id El atributo almacena información sobre el propietario actual de esa ubicación. Puede ser NULL cuando las ubicaciones están predefinidas y los jugadores compiten para ocuparlas.

La structure La tabla contiene una lista de todas las estructuras que podemos construir en varios lugares del juego. Las estructuras representan mejoras que nos permiten producir mejores unidades, realizar nuevos tipos de investigación, producir más recursos, etc. Cada estructura utilizada en el juego tiene su propio structure_name único. . Algunas posibles structure_name los valores son "granja", "mina de mineral", "planta solar" y "centro de investigación".

Podemos esperar que cada estructura se actualice varias veces, por lo que también almacenaremos información sobre su nivel actual. Cada actualización mejora el rendimiento de las estructuras, por lo que produce más recursos o nos permite usar nuevas funciones en el juego. No podemos saber el nivel máximo de actualización por adelantado, por lo que definiremos todo lo relacionado con el nivel (costos, tiempo de actualización y producción) con fórmulas. Todas las fórmulas almacenadas en la base de datos son el núcleo de la mecánica del juego, y su ajuste es crucial para el equilibrio del juego y la jugabilidad en general.

Ese también es el caso con upgrade_time_formula atributo. Un valor de ejemplo para este campo es * 30 min” , donde representa el nivel al que queremos actualizar.

En la mayoría de los casos, hay requisitos que deben cumplirse antes de que los jugadores realicen determinadas acciones. Tal vez necesitemos completar una cantidad definida de investigación antes de que podamos construir nuevas estructuras o viceversa. Guardaremos el nivel de investigación necesario para construir estructuras en prerequisite_research mesa. Las relaciones y el nivel de estructura necesarios para iniciar varias investigaciones se mantienen en la prerequisite_structure mesa. En ambas tablas, las claves foráneas research_id y structure_id se emparejan para formar una clave única. El level_required El atributo es el único valor.

Estas dos tablas, prerequisite_research y prerequisite_structure , también forman el núcleo del juego.

Para cada estructura, definiremos una lista de requisitos previos:otras estructuras y sus niveles mínimos que los jugadores deben tener para comenzar a construir. Guardaremos estos datos en la structure_required mesa. Aquí, structure_id representa la estructura que queremos construir; structure_required_id es una referencia a la(s) estructura(s) de requisitos previos y level es el nivel requerido.

La structure_built La tabla almacena información sobre los niveles de estructura actuales en una ubicación determinada. La upgrade_ongoing se establecerá solo si hay una actualización en curso, mientras que upgrade_end_time El atributo contendrá una marca de tiempo una vez que se complete la actualización.

La structure_formula tabla relaciona estructuras y recursos. El par de claves foráneas de esta tabla forma su clave única. Esta tabla también tiene dos atributos de texto que contienen fórmulas con como parámetro. Definiremos estas fórmulas, una para costos y otra para generación de recursos, en la base de datos. Serán similares a la upgrade_time_formula . Los necesitamos porque debemos definir los recursos gastados en la construcción de cada estructura. También necesitamos definir la producción de recursos después de la actualización, si la estructura genera algún recurso (es decir, la mina de mineral producirá * 20 mineral por día).

Investigación y recursos

La investigación (o tecnologías) en los juegos suele ser un requisito para la creación de otras funciones. Sin ciertos niveles de investigación, no se pueden construir nuevas estructuras o tipos de unidades. La investigación también puede tener sus propios requisitos. Uno de los más comunes es el nivel de una estructura determinada, generalmente llamada "laboratorio de investigación". O tal vez los jugadores necesitan completar un cierto nivel de investigación antes de poder comenzar una nueva investigación. Todos estos requisitos serán tratados en esta sección. A continuación, podemos encontrar el modelo de datos para Investigación y Recursos:

La research La tabla contiene una lista de todas las posibles acciones de investigación en nuestro juego. Utiliza la misma lógica que la structure mesa. El research_name atributo es la clave única de la tabla, mientras que la upgrade_time_formula El campo contiene una representación de texto de la fórmula de requisitos de tiempo de investigación, con como su parámetro. Los recursos necesarios para las actualizaciones se definen en upgrade_formula almacenado en el research_formula mesa.

Al igual que con las estructuras, definiremos la lista de todas las demás investigaciones y sus niveles que deben completarse antes de que podamos comenzar otro tipo de investigación. Guardaremos estos datos en el research_required tabla, donde research_id representa la investigación deseada; research_required_id es una referencia a la investigación de requisitos previos y level es el nivel requerido.

La investigación está relacionada con jugadores individuales, y para cada jugador – investigar ch pair debemos almacenar el nivel de investigación actual de un jugador y cualquier estado de actualización en curso. Almacenaremos esta información usando el research_level tabla de la misma manera que usamos la structure_built mesa.

Los recursos como la madera, el mineral, las gemas y la energía se extraen o recolectan y se usan más tarde para construir estructuras y otras mejoras. Guardaremos una lista de todos los recursos del juego en el resource diccionario. El único atributo aquí es resource_name campo, y también es la clave única de la tabla.

Para realizar un seguimiento de la cantidad actual de recursos en cada ubicación, usaremos el resources_on_location mesa. De nuevo, un par de claves foráneas (resource_id y location_id ) forma la clave única de la tabla, mientras que el number El atributo almacena los valores de recursos actuales.

Unidades y Movimientos

Los recursos se utilizan para producir unidades. Las unidades se pueden usar para transportar recursos, atacar a otros jugadores o, en general, saquear e incendiar.

La lista de tipos de unidades utilizadas en nuestro juego se almacena en la unit diccionario con un solo valor, unit_name; ese atributo es la clave única de esta tabla. Algunas unidades de juego comunes son "espadachín", "crucero de batalla", "grifo", "caza a reacción", "tanque", etc.

Necesitamos describir cada unidad con características específicas. Una lista de todas las características posibles se almacena en la characteristic diccionario. El characteristic_name El campo contiene un valor único. Los valores en este campo podrían incluir:"ataque", "defensa" y "puntos de golpe". Asignaremos características a las unidades usando unit_characteristic relación. El par de claves foráneas de unit_id y characteristic_id forman la clave única de la tabla. Usaremos solo un atributo, value , para almacenar el valor deseado.

La research_unit La tabla contiene una lista de todas las actividades de investigación que deben finalizar antes de que podamos comenzar la producción de un tipo de unidad determinado. El unit_cost La tabla define los recursos necesarios para producir una sola unidad. Ambas tablas tienen claves únicas compuestas por el par de claves foráneas (research_id o resources_id combinado con unit_id ) y un campo de valor (cost y level_required ).

Y ahora, la parte divertida. La producción es divertida, pero mover unidades y actuar es aún mejor. Ya presentamos la unit tabla, pero la mantendremos aquí debido a cómo se relaciona con otras tablas.

Las unidades están estacionadas en una ubicación o se están moviendo entre ubicaciones. Agregando el player_id determina quién es el propietario de la ubicación o del grupo que se mueve entre las ubicaciones.

Si las unidades solo están estacionadas en la ubicación dada, almacenaremos esa ubicación y la cantidad de unidades estacionadas allí. Para hacerlo, usaremos las units_on_location mesa.

Cuando las unidades no están estacionadas, se están moviendo. Tendremos que almacenar su punto de partida y su destino. Además, necesitamos definir posibles acciones durante los movimientos. Todas estas acciones se almacenan en el movement_type diccionario. El type_name el atributo es único mientras que allows_wait El atributo determina si una acción permite esperar en el punto de destino.

Podemos mover un solo tipo de unidad, pero en casi todos los casos moveremos muchas unidades de varios tipos de unidades diferentes. Ese grupo compartirá datos comunes y los almacenaremos en el group_movement mesa. En esta tabla, definiremos los siguientes elementos:

  • el jugador que inició esa acción
  • el tipo de acción
  • el punto de partida
  • el punto de destino
  • la arrival_time en el destino
  • la return_time al punto de partida
  • el wait_time en el destino

La return_time El atributo puede ser NULL si se trata de un viaje de ida y wait_time lo define el jugador. Las unidades que pertenecen a un grupo están definidas por valores almacenados en el units_in_group mesa. El par de claves foráneas de units_id y group_moving_id forma la clave única de la tabla. El número de unidades del mismo tipo dentro de un grupo se define en el number atributo.

Cada movimiento puede transportar recursos de un lugar a otro. Por lo tanto, definiremos una relación de muchos a muchos entre el group_movement y los resources mesas. Además de las claves principal y externa, los resources_in_group la tabla contiene solo el number atributo. Este campo almacena la cantidad de recursos que los jugadores mueven desde el punto de partida hasta su destino.

En la mayoría de los casos, los jugadores pueden llamar a otros para que se unan a su aventura. Para respaldar eso, usaremos dos tablas:allied_movement y allied_groups . Un jugador iniciará una acción conjunta y eso creará un nuevo récord en el allied_movement mesa. Todos los grupos de unidades que toman parte en una acción aliada están definidos por valores almacenados en allied_groups mesa. Cada grupo se puede asignar a una acción aliada solo una vez, por lo que las claves foráneas forman la clave única de esta tabla.

Este modelo nos da la estructura básica necesaria para construir un juego de estrategia MMO. Contiene las características más importantes del juego:ubicaciones, estructuras, recursos, investigación y unidades. También los relaciona, nos permite definir requisitos previos en la base de datos y también almacena la mayor parte de la lógica del juego en la base de datos.

Una vez que se completan estas tablas, se define la mayor parte de la lógica del juego y no esperamos que se agreguen nuevos valores. Casi todas las tablas tienen un valor de clave único, ya sea un nombre de función o un par de claves externas. Cambiar las características de las unidades y las fórmulas de producción/costo nos permitirá cambiar el equilibrio del juego en la capa de la base de datos.

¿Cómo cambiarías este modelo? ¿Qué te gusta y qué harías diferente? ¡Cuéntanos en la sección de comentarios!