Juego multijugador, en producción

El servidor decide, el navegador solo dibuja: una simulación determinista que corre igual en la máquina de producción y dentro del Chrome de quien juega solo.

Fable Football es un fútbol 2D en el que cada persona controla a un único atleta, no al equipo entero. Dos exigencias tiraban en direcciones opuestas: en un juego competitivo el cliente no puede tener autoridad sobre nada, y al mismo tiempo el modo de entrenamiento tenía que funcionar sin servidor alguno. La salida fue sacar la regla del juego de ambos lados y ponerla en un tercer lugar.

  • 60 Hz en ambos lados
    Simulación y transmisión de estado
  • ninguna
    Dependencias de runtime en el paquete de la simulación
  • 44, contadas por el propio bucle
    Baterías deterministas en el portón del despliegue
  • 154 en verde, 25 mutantes muertos
    Verificaciones de la torre de duelos, con prueba por mutación
  • 62, bajo demanda
    Sondas que abren el juego en un Chrome real
  • de 93,8% a 74,1%, monótona
    Victoria del jugador del nivel 1 al 11, medida
  • 11, entre 1,50 m y 2,20 m
    Atributos derivados de la estatura elegida

Cliente que calcula es cliente que hace trampa

El juego corre directo en el navegador, sin instalación y sin descarga: el pilar de producto es llegar a la diversión en menos de un minuto, y eso ya descarta cualquier arquitectura que pida instalador, tienda de aplicaciones o vestíbulo lento. Cada persona entra a la cancha como un atleta: la carrera, el pase errado y el gol son suyos, no de once muñecos comandados desde arriba.

La restricción que gobierna todo lo demás llegó junto con la promesa competitiva. Si el navegador decide si la pelota entró, alguien va a reescribir esa decisión, y el problema real no es el tramposo aislado: es la comunidad que se deshace cuando ya nadie cree en el marcador. En un juego donde el mérito es individual, un marcador sin confianza no vale nada.

Había, sin embargo, una segunda exigencia tirando hacia el lado contrario: el mismo juego necesitaba un modo de entrenamiento que funcionara sin servidor alguno, con latencia cero y sin costo de máquina encendida. Autoridad central de un lado, ejecución local del otro: las dos cosas a la vez, y sin dos reglas distintas envejeciendo en paralelo.

Una simulación, en un paquete que no conoce la pantalla

La decisión estructural fue sacar la regla del juego tanto del servidor como del cliente y aislarla en un paquete propio. Son cerca de quince mil líneas de TypeScript en catorce archivos, y el paquete no declara ni una dependencia de runtime: ni Phaser, que dibuja, ni Colyseus, que se ocupa de las salas en tiempo real, entran ahí adentro. Física, portero, fuera de juego y faltas no saben que existe una pantalla.

El servidor ejecuta esa simulación a 60 Hz y transmite el estado al mismo ritmo: el paso es un sesentavo de segundo y la tasa de sincronización es exactamente ese valor, los 16,67 milisegundos que encajan con el tic. El navegador manda intención, nunca resultado: hacia dónde quiero correr, cuánto tiempo sostuve el disparo. Quien valida cada toque a la pelota es el proceso del otro lado.

La física de vuelo de la pelota tiene una sola función, y es la misma en ambos lados: la mira que el cliente dibuja mientras cargás el disparo llama exactamente al código que el paso autoritativo va a ejecutar. No existe una segunda copia que pueda divergir con el tiempo, que es la manera clásica en que un juego en red empieza a mentir en pantalla: una línea prometiendo una curva que el servidor no hace.

El modo sin conexión como prueba, y el error que dejó al descubierto

El Entrenamiento corre esa misma simulación enteramente dentro del navegador, sin sala y sin red: la conexión es nula a propósito, y el mismo paso que el servidor habría ejecutado produce los mismos eventos, los mismos avisos y los mismos sonidos. Es la prueba más barata que existe de que la lógica tiene una sola fuente, si hubiera dos, los modos divergirían en la primera semana de cambios en la física.

La trampa apareció enseguida, y es la lección más transferible de este proyecto: las baterías deterministas de la simulación pasaban en verde mientras la escena estaba rota. En el entrenamiento el atleta quedaba trabado en el círculo central y la cámara no seguía la pelota, porque tres funciones de mira y cámara del cliente todavía se rendían cuando no había sala, y en el entrenamiento no haber sala es el diseño, no la falla.

El arreglo fue hacer que esas costuras conocieran el modo sin conexión, y la lección se volvió mecanismo. Pasamos a tener sondas que abren el juego en un Chrome de verdad, hacen clic en los botones, juegan y miden lo que la batería no ve: si el atleta se mueve, si la cámara sigue, si la consola acusó error. Hoy son 62, ejecutadas bajo demanda fuera del portón del despliegue, y cada clase de error que se escapa gana la suya.

El determinismo deja de ser curiosidad y se vuelve portón

Como la simulación es determinista, el mismo partido con la misma semilla produce exactamente el mismo resultado. Eso deja de ser una propiedad elegante y se vuelve herramienta: escenarios grabados corren en cada cambio y acusan una desviación de un píxel, en un tipo de software donde el error clásico solo aparece jugando.

Son 44 baterías en el portón del despliegue, y ese número lo cuenta el propio bucle, nunca está escrito en el mensaje final. La línea antigua traía un "41" fijo, y la regla de la casa es que un número citado envejece en silencio: quien entrara en la lista sin editar la frase haría que el registro anunciara 41 midiendo 42. La lista pasó a ser la única fuente del total.

Antes de volverse bucle, el portón era un comando por línea. El primer rojo abortaba el bloque y las decenas siguientes nunca corrían, así que cada envío revelaba un problema en vez de todos. Hoy todas se ejecutan, cada falla imprime el final de su propio registro y el paso solo falla al terminar, con la lista completa de lo que se rompió.

La vara más dura, sin embargo, es la prueba por mutación. La prueba de la torre de duelos tiene 154 verificaciones y mata 25 mutantes: el arnés rompe la regla a propósito, una ruptura por vez, y exige que alguna verificación quede en rojo. Una prueba que sigue en verde con la regla rota no es prueba, es decoración, y solo la mutación separa una de la otra.

Dificultad medida, no estimada

La torre de duelos es una escalera de rivales en el modo uno contra uno: cuatro torres de ocho adversarios, y la torre siguiente solo se destraba después de cerrar la anterior. La dificultad, no obstante, no es por torre ni por escalón: es torre más escalón menos uno, lo que da once niveles y no treinta y dos. El total se deriva en el código, nunca se escribe: fijar "11" ahí haría que la tabla mintiera el día en que la grilla cambiara de tamaño.

El objetivo pedido fue una curva, no una sensación: 95% de victoria del jugador en el primer nivel, cayendo dos puntos por escalón hasta 75% en el último. Lo medimos con un panel factorial de 36 políticas de jugador plausibles, y la escalera final entrega 93,8% en el nivel 1 y 74,1% en el nivel 11, monótona en los diez pares y dentro de 1,3 punto del objetivo en toda la vara.

Lo que mantiene ese número honesto es un puente entre el juego y la medición: el arnés carga una copia de la tabla y la prueba compara las dos, campo por campo. Sin eso la palabra "medido" empieza a describir a un rival que nadie juega, que es como se pudre todo balanceo medido. Y dejamos escrito el sesgo que no se va: la vara es un bot que conduce recto hacia el arco, mientras un humano gambetea, es punto de partida de playtest, no la tasa del jugador real.

Una elección del jugador, once números

Quien crea al atleta elige una sola cosa: la estatura, de 1,50 m a 2,20 m. De ella salen los once atributos de forma continua y determinista, sin distribución libre de puntos, y la misma función pura que alimenta la simulación alimenta el control deslizante de la pantalla: la vara que el jugador ve al crear el personaje es literalmente con la que va a jugar.

La queja que llegó del playtest era que el jugador alto no competía con los bajitos, y la intuición apuntaba a la falta de juego de cuerpo. Medimos, y la intuición estaba a un paso del lugar correcto: el arco de protección de pelota ya era del alto. Lo que no era suyo era la velocidad de conducción: 84,0 px/s conduciendo, contra 166,3 px/s del más bajo simplemente corriendo. En 48 de los 49 pares de estatura el portador no escapaba de su marcador ni corriendo.

La corrección fue un único punto de anclaje de la vara, y el efecto es graduado por construcción: más 1,2% en 1,50 m, más 6,8% en 1,85 m y más 17,9% en 2,20 m, con la conducción en la cima subiendo a 99,0 px/s. Medimos otra vez en una matriz de cinco estaturas por cinco, con 108 partidos por celda, para confirmar lo que el cambio no hizo: el bajito sigue adelante en posesión y en disparos. El alto dejó de ser inconducible; no se volvió el más fuerte.

Lo que se puede vender, y lo que no tiene precio

La monetización cambió de pilar por decisión de producto: el juego asume hoy un pay-to-win leve y equilibrable, en el que un ítem pago puede dar ventaja de atributo. La segunda palabra es la que hace el trabajo (equilibrable) y no se quedó en el discurso: se volvió una traba ejecutable en el catálogo, cobrada por código.

La ventaja en puntos fijos de atributo está prohibida, y el motivo es un número medido: el mismo "más N" rinde hasta 4,04 veces más para una estatura que para otra, así que no existe techo de panel que lo vuelva justo entre biotipos. Solo la forma porcentual pasa, porque rinde la misma proporción para todos por construcción y el panel de administración regula el valor sin necesidad de despliegue.

Y hay una categoría que sigue sin precio alguno: la ventaja de percepción. Ver mejor hacia dónde mira el adversario es información, no fuerza: no existe un "menos 3% de ver" para cobrar a cambio, y por eso no se equilibra con número alguno. El portón midió 32 direcciones en 5 regímenes con el pelo pintado del color de la piel, el peor caso posible, en dos ejecuciones idénticas byte a byte; tres cortes reprobaron y quedaron fuera del comercio, con su geometría intacta dentro del juego.

La traba se cobra en las dos puntas: en el validador de escritura, en el servidor, y en el de lectura, en el cliente. El catálogo es dato editable desde el panel administrativo, y una traba solo en la escritura sería sorteable por cualquier fila que ya estuviera en la base antes de que la regla existiera.

El juego está en el aire con partida en línea, entrenamiento sin conexión y la torre de duelos, en una máquina en São Paulo que escala a cero cuando nadie está jugando y levanta una máquina efímera para aplicar migraciones antes de que la nueva versión reciba tráfico. Una sola instancia, a propósito: el estado de las salas vive en memoria, y dos máquinas pondrían a los jugadores en canchas distintas sin verse nunca. La regla del juego, esa, sigue teniendo una sola fuente: probada por el servidor y por el navegador al mismo tiempo.