La .NET CONF 2024 acaba de terminar. Descubre las NOVEDADES de .NET 9 junto a los CAMBIOS que trae C# 13.
Puedes ver el contenido de este vídeo junto con su curso en el modo vídeo (similar a Udemy) si pulsas aquí.

Diseño y Desarrollo de Juegos de Navegador

05 Aug 2024 20 min (0) Comentarios

Desde siempre he querido hacer un juego similar a un Ogame, un TribalWars o Hattrick, por el motivo que sea siempre me ha encantado la idea, pese a que nunca he tenido tiempo real de para invertir en este tipo de juegos, ya que son juegos en su mayoría a largo plazo, especialmente el Hattrick, donde te va a llevar años conseguir objetivos. 

 

Hace unas semanas, me plantee el crear uno, y después de llevar un rato  programando me di cuenta que lo que tenía que hacer, antes de nada, es un diseño. 

 

Si bien es cierto, esto es lo que yo he sacado y puede no estar correcto al 100% o hay cosas que posiblemente tu cambiarías. Pero como punto de partida y como exploración me parece que es muy interesante. 

 

 

 

1 - Qué es un juego de navegador? 

 

Un juego de navegador, como su nombre bien indica es un tipo de juego al que accedemos a través del navegador y consiste en ser un manager o un gestor de un entorno o sistema. Este tipo de juegos se basan en la gestión de recursos ya sea ser el dueño de un equipo, donde puedes ampliar el estadio, contratar jugadores, personal, etc (Hattrick), o el jefe/dueño de un planeta donde tienes que administrar la gestión de recursos, ataques, etc (Ogame).

 

La gracia es que compites contra otras personas para ver quien es el mejor (PVP), donde prima una estrategia a largo plazo, en el caso de Hattrick, donde eres un entrenador de futbol, te puede llevar varios años (o incluso más) subir un par de divisiones.

Básicamente se puede resumir que es jugar al excel. * Esto es un meme para todos los fans del Fútbol Manager. 

 

A día de hoy, a no ser que lo hagas por aprender, crear este tipo de juegos es un suicidio porque el mercado de juegos móviles se ha comido completamente el mercado, al final tu competencia es el clash of clans y similares, con los que es imposible competir siendo una sola persona debido a todas las técnicas abusivas que utilizan, donde parecen mas una tragaperras que un juego, pero ese es otro tema.

 

 

1.1 -  Juego de navegador en tiempo real

 

Cuando era una adolescente los juegos de navegador se hicieron algo populares, de hecho había uno que destacaba, no hablo del habbo, que no lo he jugado nunca y no se si iba en el navegador.  

 

Lo que hablo es del Bruto, igual que Hattrick u Ogame, al bruto se jugaba en el navegador, pero tenía una diferencia el PVP era en tiempo real. Lo que hoy en día haríamos con Websockets, o SignalR si trabajas con .NET.

Así que si en tu caso quieres tener algo de tiempo real, como ves, no es complicado de añadir.

 

 

2 - Diseño del juego

 

2.1 - Elección del estilo de juego

Inicialmente lo que había pensado es un juego de piratas, donde tienes barcos, con tripulación que van a la mar a pegarse, tenía pensado hacer un mundo lleno de islas,  vamos como one piece. 

 

Pero, esto trae consigo varias dificultades a tener en cuenta. Que vienen siendo los barcos, que haces con ellos, me gustaría que fuera realista, lo que significa que no puedes atacar con 100 barcos y los 100 barcos desembarcar, eso no funciona así, cada isla debería tener un % de tierra donde se puede desembarcar y a raíz de eso continuar. 

 

Si te fijas, solo con la primera idea de diseño se nos complica la implementación, porque son detalles, pequeños, pero importantes que te consumen todo el tiempo.

 

Así que llegado a este punto aparqué el tema de los piratas y decidí ir por algo más sencillo. Las batallas a pie. Aquí podría coger y hacer lo mismo, coger mi serie favorita y hacer el diseño a raíz de esa serie, pero, mi idea era hacer un boceto de la idea, tener algo palpable y cogí lo que seguramente todos estáis pensando. El Age of Empires, soldados, arqueros, caballeros y una vez pasas el boceto armas de asedio y coches que disparan 👀. 

Coches que disparan age of empires

La idea es plasmar eso en un juego que no es en tiempo real y en el navegador.

Si te pones a investigar podrás ver que esto ya existe y se llama TribalWars y salió en 2003 (aunque hay una segunda versión), así que bueno, no lo sacaremos a producción, pero nos servirá para aprender y estrujarnos el cerebro un buen rato. 

imagen tribalwars

Una vez tienes la temática, da igual si es la edad media (TribalWars), una simulación de la antigua grecia (Ikariam), o una versión alternativa de Star Wars (Ogame), todos son más o menos iguales, tienes tu ciudad/planeta y atacas a otros, el coste de atacar, tanto en recursos como en tiempo, se basa en la distancia que tienes hasta ese lugar. En este momento ya te estarás montando tus batallitas en tu cabeza, viene el funcionamiento global. 

 

 

2.2 - Recursos y progresión

 

Una de las partes más importantes, o la que más de cualquier juego es mantener a la gente interesada en él, no quiero decir enganchada, porque para eso hay que hacer técnicas abusivas que no comparto, pero si interesada en estar conectada constantemente. 

Y para ello necesitas que la progresión sea muy buena, no quieres ni llegar al nivel máximo en un día ni que sea completamente imposible.  Hay que hacerlo de forma gradual.

 

Aquí es donde entra el tema de los recursos ya que es la forma más sencilla de regular la progresión.

Todo este tipo de juegos tiene un sistema de recursos, ya sean recursos básicos con los que construir otros edificios, o sean monedas o tokens que hacen referencia al dinero real.

 

En esta sección hablaremos de los recursos básicos

En resumidas cuentas necesitas recursos tanto para crear tropas como para mejorar edificios. 

 

Por poner un ejemplo podemos decir que los recursos son la comida, la madera, el hierro y la piedra. Cada uno de estos materiales se obtiene de un edificio diferente.

Por ejemplo, la madera se obtiene de una serrería, la piedra de una cantera, el hierro de una mina y la comida de la granja. 

 

Si quisiéramos hacerlo realista deberíamos poder poner límites a cuánto hierro podemos extraer de una mina, cuántos árboles hay en el bosque o un número mínimo y máximo de granjas, pero un realismo extremo no solo es dificil de conseguir técnicamente sino que puede hacer que nuestros usuarios más casual se piren, y a los hardcore les da un poco igual. Así que lo recomendable es tener un edificio que obtenga X recursos por hora. Así como unos requerimientos para subir de nivel y que sea capaz de conseguir más recursos por hora. 

 

A esto, hay que añadirle el tiempo donde los primeros niveles son muy rápidos, para dar un signo de progresión al usuario, mientras que los últimos son mucho más lentos, para mostrar que es una tarea difícil y que tienes que pensártelo mucho antes de seleccionar una mejora.

Lo mismo aplica para las tropas, las tropas tienen un coste tanto de recursos básicos como de tiempo.

 

 

2.3 - Monetización en los juegos de navegador

 

Para bien o para mal, tenemos que monetizar nuestra aplicación ya que los servidores no son baratos. Este tipo de juegos nos permiten tener una ventaja administrativa cuando pagamos por premium, no son pay to win, 

Esto quiere decir que, cuando pagamos, ni los edificios se hacen antes, ni las tropas se hacen antes, ni cuestan menos, ni son más fuertes o no obtenemos recursos extra.

NOTA: Ogame si lo hace 🤦

 

Entonces, ¿Para qué alguien pagaría? 

 

¿Recuerdas cuando en la sección anterior hemos dicho que la progresión es lenta? ¿Qué pasa si un edificio tarda 10 horas en construirse y eso significa que termina a las 3 de la mañana? Pues que para poner otro, o perdemos unas muy valiosas horas de construcción mientras dormimos o pagamos premium donde tenemos una funcionalidad que nos permite indicar qué edificio se mejorará después de forma automática. 

 

Lo mismo pasa por la noche, podemos programar ataques para que sucedan en horario nocturno sin tener que estar nosotros presentes. Como vemos son ventajas, que son administrativas, no aceleran la progresión haciéndose completamente injusto para el resto de jugadores. 

 

Cuanto quieras poner en la modalidad premium va a depender de tí, pero tiene que ser justo lo necesario para que los usuarios paguen y los usuarios gratuitos no sientan que es imposible jugar si no pagas. 

 

 

En el caso concreto de hattrick que es un simulador de entrenador de fútbol hay 4 tipos diferentes en las suscripciones premium -https://www.netmentor.es/entrada/suscripciones-stripe-, permitiéndo en las dos más caras administrar otro equipo. (De hecho esa es la única diferencia entre gold y platinum) .

 

hattrick

NOTA: Hattrick está programada en .NET, por lo menos la interfaz es ASP.NET Framework -https://www.netmentor.es/entrada/explicacion-versiones-dotnet-.

 

 

2.4 - El motor de juego

 

El motor de juego no es como un juego “normal”, no estoy hablando de un Unity o Godot o hacerte tu propio motor, ya que el motor de este juego va a ser tu servidor que va a tener corriendo toda la infraestructura. 

 

Lo que estoy hablando es de el motor de combate en el caso de TribalWars o de nuestro juego de combate, el motor de los partidos en el caso de Hattrick.

 

Es muy importante mantener un motor que sea lo más “realista” y neutro posible, para que así sea justo para todo el mundo. 

Porque te puede pasar que tu juego no esté balanceado como le pasó a la primera generación de Pokémon con los tipos psíquico que no tenían counter y todo dios jugaba mewtwo, eso sí, el mejor el mio con psíquico, recuperar, rayo hielo y trueno.

 

Aquí lo ideal es hacer muchas simulaciones hasta verificar que no hay una composición que destruye el balance del juego. 

 

 

2.4.1 - El motor gráfico del juego

Si bien es cierto que lo más importante es el balance de las tropas, la parte gráfica también es importante, en nuestro caso no tenemos mucho, con tener una aldea que nos sirva como plano y edificios que van cambiando de forma dependiendo del nivel sería suficiente. Esto si quieres hacerlo gráfico, si quieres jugar completamente en un simulador de hoja de excel , con mostrar la información por pantalla es más que suficiente (Ogame, lo hace, o hacía así) 

 

 

 

3 - Implementación del motor de juego 

Para nuestro caso lo principal es el combate, y si bien es cierto aquí no voy a descubrir el santo grial, si que le he dado varias vueltas y tengo una versión que ya veré si algún día pongo en GitHub. 

 

Cuando hablamos de batallas estamos hablando de varias cosas, batallones y combate son las más básicas. Entonces, cómo afrontamos la pelea? 

Podríamos hacer algo similar a lo que hace el juego risk, si atacas con 10 y el rival defiende con 12 tiramos dados hasta que uno de los bandos se queda sin tropas. 

 

Implementar eso es lo más sencillo, seguramente deberíamos implementar algo como, un soldado vale un punto, los arqueros 0.8 y los jinetes 1.3 o algo así y vamos repitiendo. 

 

Pero, yo soy muy fan de los RTS (juegos tipo age of empires) y los juegos por turnos, así que lo que yo pensé es lo siguiente, y lo voy a mostrar con el proceso mental que YO lleve.

 

Lo primero fue imaginarse una pelea 1 vs 1, ya que es la mayor simplicidad. 

En mi caso, un soldado y un arquero. 

 

Obviamente el arquero puede atacar a distancia, y el soldado no, así que no puedes ponerlos uno delante de otro y ya, eso no funciona así en la realidad. 

 

Lo que se me ocurrió fue poner un mapa donde las tropas están separadas por 10 unidades, estás unidades hacen referencia a distancia, ya bien sea la velocidad de movimiento, o el rango, por ejemplo, puse que el arquero tenga 7 de rango.

infantry vs arch

 

Esto quiere decir que para que el arquero pueda golpear con la flecha al soldado, alguien tiene que moverse.

 

Y para permitir que las tropas se muevan tenemos que saber cuantas veces, a lo largo de la partida, se pueden mover. Aquí es donde integré el sistema de turnos. Cada batalla tiene un número de turnos aleatorio entre 8 y 12, por qué esos números? Pues no lo sé pero es la primera versión así que 8 y 12 es tán válido como 14 y 25.

 

Otro elemento clave en los juegos por turnos es que un usuario hace todo su movimiento (ya sea una tropa o todas) seguidas sin intervención del enemigo. Para mi esto no es justo, en mi opinión debería ser ambos se mueven y una vez se mueven atacan y así es como lo hago yo los turnos suceden de forma simultánea. 

 

En nuestro caso, llegamos al primer paso del turno, donde están separados por 10 unidades. 

 

Como el soldado solo puede atacar a lo que está en una unidad de distancia, tiene que moverse y lo mismo para el arquero, como no llega a disparar, tiene que moverse.

Eso implica que ambos se van a mover, lo cual es MUY importante. Por que? Porque si el soldado se moviera 3 el arquero no tendría que moverse y está a 7 unidades de distancia PERO como el arquero también tiene que andar, este se pone a 5 unidades, lo cual es importante porque el soldado llegará antes a poder atacar. Espero que haya podido explicarme.

Y por supuesto lo mismo ocurre a la hora de atacar, si dos tropas atacan lo hacen a la vez y no es hasta el final del turno que se calcula quién ha muerto.

 

Nota: Por ahora las tropas atacan una vez por turno. 

Esta sería la situación al final del primer turno:

arch vs inf

Nota: He revisado el código, el arquero se mueve 3 y el soldado 2.

 

Por supuesto, el arquero tiene una pequeña probabilidad de fallar, y el daño que el soldado recibe tiene en cuenta el daño de la flecha y si tiene armadura o no, etc.

 

 

En el siguiente turno el soldado se moverá pero el arquero no, por lo que únicamente atacará. Y así hasta que o uno de los dos muere, o los turnos se acaban. 

 

 

3.1 - Implementación de batallones

 

Pero claro, nadie ataca solo con una tropa, ni defiende con una tropa, lo ideal es batallones, por ahora mantengamos únicamente una sola unidad dentro de nuestros batallones, la pelea puede ser tal que así:

batallon1

Este ejemplo es muy básico pero nos sirve para ilustrar varios problemas que vamos a enfrentarnos.

 

El primero es el tamaño del campo de batalla, 10 unidades de diferencia no es suficiente. Y necesitamos un tamaño de ancho del campo de batalla, donde idealmente no todos los pueblos tendrán el mismo y no solo eso, sinó que en cada flanco de tu pueblo, deberías de tener uno diferente y sea parte del atacante el tener que investigarlos para saber por dónde atacar. 

 

Algo que notamos es que no todos los arqueros llegan a los mismos sitios con 7 unidades, por ejemplo, el arquero de arriba a la derecha después del primer turno puede atacar a las siguientes posiciones: 

archer distance

Lo que quiere decir que para atacar a los de abajo, se tiene que mover en el tablero. 

 

Una posible solución es coger y tratar a todas las tropas como una sola y trabajar sobre eso.  Y es una solución posible, pero…. Bueno, un poco meh, no nos vamos a engañar. 

 Habría que investigar si merece la pena invertir tiempo en interacciones individuales o en grupo a la hora de implementarla. 

 

Pero sigamos, porque en nuestro batallones no tenemos únicamente soldados y arqueros, también tenemos caballeros o lanceros, los cuales son ideales contra la caballería y si nos basamos en la peli de 300, los lanceros tienen un rango de 2 unidades.

batallon

Creo que llegados a este punto está claro que necesitamos un mapa de batalla mucho más grande, posiblemente una distancia de unidades de 30 o quizá más, depende en cuanto quieras poner el límite de unidades en el campo. Y mucho más extenso hacia arriba y hacia abajo. 

Hay muchos más detalles con respecto al movimiento, que dos tropas no puedan estar en una misma casilla o pasar por encima de otra tropa, que para implementarlo necesitas un algoritmo de pathfinding.

 

 

3.2 - implementación de formaciones

 

Tener a las unidades esparcidas por el mapa, nos permite elegir formaciones, la que hemos visto en la imagen anterior se podría considerar como una formación en línea, pero también podríamos decir que es la de por defecto. 

 

Pero, qué pasa si quieres lanzar un mayor ataque por los costados y menor por el centro, quizá sabes que tu defensor utiliza cierta formación defensiva, y lo quieres acorralar haciendo agujeros en esas posiciones. 

 

O si sabes que solo defienden con artillería, tener las tropas separadas es importante para que así la artillería no golpee a varias. Sí, esto es muy común en el age of empires, sí, he jugado mucho. 

 

Para mí, la formación es algo básico dentro de los juegos de estrategia y primordial a la hora de crear un motor. 

Por supuesto tiene la pega que tendrías que elegir dicha formación antes de ir a pelear. Lo cual tampoco debería ser un problema muy grande siempre y cuando limitemos el número de tropas posibles. 

Con la formación entran las órdenes, quizá quieras que solo un flanco ataque mientras el otro se queda resguardado para atacar después, cuando los soldados se hayan movido.

 

Todo esto que hemos visto son pequeñas variables que hacen la programación de un motor para este tipo de juegos un verdadero desafío, así como super entretenido. 

 

 

4 - Arquitectura de un juego de navegador

 

Como punto final, hablemos de la arquitectura que conlleva un juego de navegador. Podemos ponerlo todo en un monolito que y que cuando los ataques sucedan simplemente ejecutar una tarea en segundo plano que nos de el resultado y ya. Y para una MVP es lo que deberíamos hacer.

 

Pero, qué gracia tiene hacer este post y decir que con un monolito nos sirve, hagamos una arquitectura distribuida de como sería lo ideal. 

 

Está claro qué el FrontEnd es muy básico, vistas normales, ya bien quieras utilizar SPA o no, al final solo hay que mostrar información seniclla por pantalla, y como mucho utilizar pooling cuando uno de los contadores, ya sea el de enviar un ataque o el de los recursos termina simplemente refrescar esa seción.

 

 

La parte que se nos puede complicar un poco es la parte del BackEnd. 

Por ejemplo qué hacemos cuando pulsamos en subir un edificio? En la interfaz, nos saldra un temporizador que indica cuanto tiempo necesita para subir, pero, y en el backend? 

 

Lo primero será bloquear la BBDD para que nada más pueda actualizarse.

block dbPero además debemos asegurarnos que cuando el contador llegue a 0 subamos el nivel del edificio y la interfaz se nos desbloquee. 

 

Para ello, lo que necesitamos es un job scheduler distribuido, otra opción es tener un sistema de tareas en segundo plano que lance eventos cuando una acción tenga que suceder.

 

Por ejemplo, volvamos al caso de antes, cuando el usuario  pulsa el botón de subir de nivel un edificio, vamos a generar un evento (Pub/Sub) el cual será leído por el sistema que utilizaremos como scheduler.

 

Llegada la hora el scheduler lanzará otro evento el cual contendrá la información para subir el edificio de nivel y que será escuchado por un consumidor con acceso a la base de datos:

pub sub juego de navegador

Lo mismo sucede para los ataques, generamos un evento el cual nos indica cuando vamos a atacar, porque, mientras las tropas están atacando, debemos bloquear el número de tropas disponibles de en la ciudad, para que así no puedan atacar a otros objetivos.

Así que una vez llegan el scheduler genera un evento, y el consumidor cuando el evento se genera calcula la pelea, el reporte y “devuelve” las tropas resultantes, la cuales se tienen que actualizar al volver a base, para lo que necesitamos otro sistema con otro scheduler. 

attack architecture

Toda esta interacción de eventos siendo lanzados de unos sitios a otros sucede en milisegundos y lo hacemos así por múltiples motivos. Primero nos garantizamos que los eventos suceden y si no lo hacen porque un sistema está caído, siempre podemos volver a ejecutarlos todo tal y como estaba en aquél momento. 

 

La separación de responsabilidades también es muy importante, o la escalabilidad. Al principio de la vida del juego, muchos más edificios subirán de nivel que ataques serán realizados, mientras que después de un tiempo muchos más ataques sucederán en comparación a la subida de nivel de edificios.

 

Nota: hemos obviado los casos de uso de cancelar una actualización de edificio o cancelar un ataque, pero creo que se entiende con lo que he hecho. 

 

Si tienes dudas sobre los sistemas distribuidos no olvides que en esta web tenemos el mejor curso en castellano sobre los mismos y encima completamente gratuito.

Enlace al curso de Sistemas Distribuidos (gratis) 

 

Finalmente quiero hacer una mención especial a algo que se me acaba de ocurrir, sabiendo lo que se, siempre podría tener la API abierta (auth obligatoria) y que cada persona se pudiera crear un FrontEnd si así lo deseara, que no te gusta como he creado la web? No te preocupes puedes montarte el tuyo ;)

 

Si os gusta el contenido no olvidéis dejar un mensaje abajo y quizá podamos hacer una serie creando dicho juego!

 


Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2024 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café