Escribir una arena PvP por turnos con movimientos simultáneos

En este artículo hablaré sobre lo que impulsó la creación del juego en un género tan inusual, qué tipo de género fue, cómo progresó el desarrollo, qué dificultades encontramos y cómo menos de un año de trabajo en las noches logramos crear un prototipo totalmente jugable.



En la primavera de 2017, me encontré con un incentivo Atlas Reactor . El juego era una especie de mezcla salvaje de ajedrez, póker y mobs, y una combinación tan inusual de géneros realmente me llamó la atención. Se convirtió en mi juego favorito, participé en torneos y eventos en línea, y todo estaría bien, pero ...

En el verano de 2019, los servidores estaban cerrados, porque Debido a la baja popularidad del juego, su apoyo no fue rentable para el editor. El juego se creó en el modelo de juego como servicio , por lo que el cierre de los servidores convirtió a los clientes en fragmentos de código rotos.

Debido a la combinación única de géneros de juegos similares, simplemente no había ningún juego en el mercado, pero realmente quería jugar algo así.

Poco después del cierre, me encontré con una publicación en el reddit que un grupo de entusiastas de ex jugadores decidió crear un servidor privado y ajustar el código del cliente para trabajar con él, pero no tenía un deseo especial de unirme a ellos. Nunca me ha interesado la ingeniería inversa y, además, dicha actividad no parece demasiado legal.

Al final, decidí reunir personas y organizar el trabajo sobre el "heredero espiritual", para hacer un juego con una mecánica similar, pero nuevos personajes, habilidades, cartas y ENT. Comenzamos a trabajar con puro entusiasmo por las tardes y los fines de semana. Queríamos aportar algo propio al género, agregar variabilidad y profundidad, y corregir los defectos del original. Desde el principio, estaba claro que el juego no se volvería súper popular, pero estaba seguro de que al menos varios miles de personas podrían estar interesadas en él. Al menos, fanáticos del cerrado Atlas Reactor.

Como se Juega


En general, la acción recuerda al XCOM multijugador, pero con un 100% de posibilidades de golpes y héroes (como en el género MOBA).

La idea del juego es que todos los resultados están completamente determinados por las acciones fijas de los jugadores. La aleatoriedad está completamente ausente, y la variación es lo suficientemente baja como para que los jugadores experimentados puedan calcular todos los resultados probables y actuar sobre la base de esta información. Para reducir la variabilidad, se usa un campo de juego plano dividido en celdas, es decir, los héroes solo pueden pararse en el centro de las celdas (aunque las habilidades generalmente se aplican en cualquier lugar, sin referencia a la cuadrícula).

Por lo general, 8 personas participan en un partido. Se dividen en 2 equipos de 4 personas, y cada uno controla un personaje. Sin embargo, debido al paso a paso, nada impide crear un modo en el que solo participan 2 personas, y cada uno controla los cuatro personajes de su equipo.

El juego se divide en movimientos. Cada movimiento se divide en dos etapas: decisión (toma de decisiones) y resolución(visualización de los resultados de las acciones seleccionadas). La dinámica se agrega por el hecho de que ambas etapas ocurren para ambos equipos al mismo tiempo (este tipo de paso a paso se llama We-Go): no hay tal cosa que un equipo piense y el segundo simplemente espere, mirando la pantalla donde no sucede nada. En cambio, ambos equipos toman decisiones y observan los resultados al mismo tiempo. La simultaneidad de los movimientos y la presencia del campo de visión de los personajes conduce al hecho de que el juego no puede atribuirse a juegos con información completa .

Decisión- una fase en la que los jugadores tienen la oportunidad inmediata de elegir las acciones que desean. El campo de juego se "congela" durante varias decenas de segundos, y los jugadores deben elegir qué acciones específicas tendrán que realizar los personajes controlados por ellos cuando termine la "parada de tiempo". Cada jugador ve qué acciones van a tomar sus aliados, pero las acciones elegidas por los oponentes están ocultas.

Resolución : la fase en la que se realizan las acciones seleccionadas. Con el tiempo, toma aproximadamente lo mismo que Decisión, o un poco menos. Durante el juego, los jugadores no tienen control: simplemente observan lo que está sucediendo y reflexionan sobre las acciones para el próximo movimiento.

La resolución se divide en fases. Las fases van secuencialmente, y para cada habilidad los jugadores saben de antemano en qué fase funcionará. En este caso, el orden de operación de las habilidades dentro de una fase no importa.



Como regla general, el daño se hace en la fase de Explosión, por lo que las habilidades defensivas se disparan antes: puedes aplicar escudos en la fase de Preparación o moverte (esquivar) en la fase de Dash. Pero al esquivar, el enemigo puede recibir daño si pasa a través de una trampa (establecida por el jugador en la fase de preparación). Además, si el enemigo no esquiva, sino que simplemente permanece en su lugar, entonces la trampa no funcionará y no le causará ningún daño. Lo mismo con los escudos: si no atacas a un personaje protegido, simplemente se quemarán al final del turno, sin tener ningún efecto. El interés aquí es que, como se mencionó anteriormente, las acciones de los oponentes en el momento de la toma de decisiones están ocultas y, por lo tanto, deben preverse.

El valor de daño típico no excede de 35 para facilitar que los jugadores cuenten en sus mentes. Los efectos de estado y las habilidades son pocos por la misma razón. El modo de juego principal es el deathmatch habitual, que sube hasta 5 muertes o 20 movimientos.

Implementación


Decidí escribir en C # (ya que este es mi idioma principal), y elegí Unity como motor (ya que no tenía experiencia previa en la creación de juegos, pero de forma nativa es compatible con C # y es bastante amigable para los principiantes).

Los juegos por turnos no requieren una gran cantidad de recursos, por lo que desde el principio consideré las opciones más económicas para alojar el servidor principal. Hubo una idea de alojar en heroku (porque generalmente es gratis), pero reiniciar la aplicación al azar al menos una vez al día es extremadamente inconveniente. Se detuvo en VPS con Linux por 45 rublos por mes.

Dados los recursos limitados en el alojamiento (especialmente, muy poco espacio en el disco duro) y el hecho de que toda la lógica del juego funciona en 2D, decidí hacerlo en .NET Core (escribiendo mi ligero motor 2d para calcular las áreas afectadas por las habilidades), y usar Unity puramente para visualización del lado del cliente. Esto hizo posible controlar simplemente el campo de visión de los caracteres en el lado del servidor y enviar a los clientes solo la información que deberían conocer. Se validan las acciones seleccionadas de los jugadores antes de procesarlas en el servidor, lo que excluye por completo la posibilidad de hacer trampa.

Para la comodidad de los jugadores, un simple iniciador para WinForms lo eliminó, lo que, si es necesario, descarga la versión actualizada del cliente desde Dropbox.

Ahora me detendré con más detalle en los momentos más interesantes (o que causan dificultades) que encontramos al desarrollar el juego.

El procedimiento para usar habilidades


Como se mencionó anteriormente, el resultado obtenido no debe depender del orden de aplicación de habilidades dentro de la fase. En el servidor, las habilidades se usan en orden ascendente de la identificación del héroe, pero el jugador no debe pensar en ello. Esta condición impone restricciones sobre qué y en qué fases pueden ocurrir (los diseñadores de juegos se ven obligados a tener esto en cuenta al crear habilidades).

Por ejemplo, una vez en la fase de preparación puede aplicar escudos, entonces no puede hacer daño en él (de lo contrario, dependerá de la identificación, el daño pasará a los escudos o directamente a la salud antes de que se apliquen). Del mismo modo, dado que el daño se puede infligir en la fase de Explosión, no está permitido aplicar el efecto de estado "Poderoso", que aumenta el daño hecho por el héroe. Reglas similares aparecieron para todos los elementos del juego.

Lógica de juego simple


La idea misma del juego es que los jugadores pueden calcular en su cabeza todo el desarrollo de eventos dentro del curso y, por lo tanto, la lógica de todos los elementos del juego debe ser simple e intuitiva. Pero con la implementación del plan surgieron muchas dificultades.

En primer lugar, el movimiento . Los héroes pueden moverse durante las fases Dash y Move, y este movimiento debe ocurrir simultáneamente. Se permite que dos héroes estén en la misma celda mientras se mueven, pero al final de las fases de movimiento, no debe quedar más de un personaje en cada celda.

La regla más simple para resolver conflictos al final del movimiento es "quien se levantó primero, eso y zapatillas". Si el héroe ha viajado mucho antes de estar en una celda "controvertida", entonces debe ser empujado hacia atrás, y el que ha recorrido un camino más pequeño debe dejarse en su lugar. Si los héroes llegaron a su destino, después de haber recorrido la misma distancia, empujarlos a ambos. Debido a su determinismo, se decidió hacer retroceder a los héroes a lo largo de las trayectorias de su movimiento. La repulsión se repite hasta que se resuelvan todos los conflictos.

El segundo problema es la equivalencia . Supongamos que queremos crear un perfil que, cuando golpea a un enemigo, le inflige daño y rebota automáticamente al más cercano.para él un personaje. El problema aquí es una combinación de "automáticamente" y "más cercano". Los héroes se encuentran en un campo a cuadros, lo que significa que al lado del objetivo principal a la misma distancia mínima puede haber varios personajes.

¿Qué hacer?
  • Ricochet en ambos
  • Ordenar héroes alfabéticamente
  • Ordenar por ID de jugador
De hecho, la solución es que tenemos más datos: la posición desde la que se disparó el disparo. Si no puedes elegir un objetivo más cercano para el rebote, entonces puedes ordenar a los héroes en el sentido de las agujas del reloj, donde el objetivo principal es el centro, y el héroe que aplicó la habilidad es la posición inicial.

Geometría honesta


Al final resultó que, jugar con geometría honesta no es interesante. Las paredes son impermeables a la mayoría de los disparos y bloquean el campo de visión de los oponentes, y además sirven como refugios (y si el daño proviene del lado del refugio, entonces se reduce en un 50%). Sin embargo, las paredes limitan extremadamente el área afectada para el héroe mismo, y debido a esto, los jugadores no vieron ninguna razón para usarlas.

Tiempos de pintura

— , — . ( ) — . , 90 .

Se decidió verificar el rango de visibilidad no solo entre los centros, sino también entre algunos puntos específicos.

Pintar dos


Entonces, el uso de cuatro puntos adicionales a lo largo de los bordes del héroe redujo la "zona muerta" a 60 grados (que ya se ha vuelto bastante jugable).

Como resultado, las paredes se volvieron realmente útiles.

Pintar tres

, 50% ( , ).

Los puntos adicionales se encuentran exactamente en el medio entre el centro de la celda y sus bordes, y esta elección no es accidental. Para los ataques rectangulares, es muy importante desde dónde se dispara el disparo (ya que este punto se usa para calcular los rebotes de paredes, explosiones y algunos otros modificadores de ataque). Un algoritmo simple hizo posible cambiar automáticamente el punto de partida dentro del héroe, dependiendo de la posición del mouse. En este caso, el punto se ubica para maximizar el alcance del disparo cerca de la pared.

Aquí hay un enlace al gif (20Mb) , donde puede ver cómo funciona el cambio automático del punto de disparo.

Localización


Para agregar localización, utilicé string.Format (para que los cambios equilibrados en los números de daño no crearan nuevas líneas) y una placa de Google. Todas las cadenas utilizadas para mostrar en la pantalla están envueltas en un método que interpola y compara el diccionario con las traducciones conocidas. Al comienzo de la versión debut del juego, las traducciones de la placa de Google se cargan en un archivo de texto en formato json, y las líneas del código fuente sin traducciones se descargan automáticamente a la misma placa de Google en el primer intento de mostrar en la pantalla. En la versión de lanzamiento del juego, por razones obvias, no existe una funcionalidad en línea para trabajar con la tabla, y las traducciones simplemente se cargan desde el archivo de texto existente al inicio.

Para los traductores, la solución no era muy conveniente (porque cambiar una palabra conduce a la creación de una nueva línea en la tabla), pero era muy simple de implementar y no cargaba a los programadores con el trabajo con recursos. Sería ideal si las líneas no cambiaran durante el proceso de desarrollo, pero este no fue el caso con nosotros.

Rastrillo


Ahora, lo más interesante. Algunos consejos obvios que pueden ayudar a los programadores novatos que deciden cortar su proyecto favorito en un equipo de personas de ideas afines.

  • Si es posible, no reinvente la rueda.
    Si el problema está muy extendido, entonces debería haber muchas soluciones preparadas. Encontrar una solución preparada adecuada puede llevar menos tiempo que escribirlo usted mismo desde cero (especialmente si el problema es complejo).
    . , . , , . NetworkStream-, TcpClient- Json. , , . 30 ( MagicOnion, )

  • — , . — . . — . — .

  • — , . - summary readme. .
  • ,
    . . — , — , , .
  • Git — ,
    , . .
  • ,
    . .
  • ,
    . , , , , . , , , .


Resultó crear un prototipo jugable en menos de un año. Parte de la comunidad activa se ha unido al desarrollo o las pruebas, por lo que ahora se realizan al menos algunas coincidencias casi todos los días. Es realmente genial ver cómo la gente disfruta del juego, en cuya creación participo activamente.

Personalmente, durante el trabajo en el proyecto, aprendí inglés hablado (ya que la comunidad es internacional), gané experiencia trabajando con Linux, programando y usando Unity. Los proyectos de mascotas son geniales.

Con el tiempo, definitivamente agregaremos capacitación para nuevos jugadores, modelos y animaciones normales, un menú adecuado y una interfaz de usuario más conveniente en general. Como los buenos modelos 3D son muy caros, crearon una cuenta en Patreon y la comunidad comenzó a apoyarnos financieramente.

Enlaces para los interesados ​​en la idea.
Discord-. .

, , - — , Atlas Reactor

All Articles