Todos los artículos

Cómo monté el multijugador en menos de un mes: lecciones de un rescate

Cuando descubrimos que la persona responsable de nuestro sistema multijugador se estaba inventando el progreso, tuve que construir todo desde cero. Así lo abordé y esto es lo que aprendí.

Unity Multijugador Técnico

El sistema multijugador de nuestro juego estaba roto. La persona que habíamos contratado para arreglarlo llevaba semanas inventándose los informes de progreso. Cuando por fin probamos su implementación, nada funcionaba. Lo despedimos.

Ahora el marrón era mío, y teníamos un mes.

El contexto

El juego era un sandbox de decoración de casas multijugador. Los jugadores necesitaban ver las casas de los demás, visitarlas e interactuar en tiempo real. El sistema existente era poco fiable—desyncs, conexiones caídas, corrupción de estado.

Nuestro stack era Unity con Steam como plataforma de distribución. Elegí Netcode for GameObjects como framework de networking y Steamworks para la capa de transporte y matchmaking.

Había trabajado con otras soluciones de networking antes—Mirror, Photon, el viejo UNet—pero Netcode for GameObjects era relativamente nuevo para mí. La documentación era decente pero incompleta. Iba a tener que aprender sobre la marcha.

El enfoque

Cuando estás bajo presión, la tentación es ponerte a programar ya. He aprendido que eso suele ser un error.

Pasé los primeros días simplemente pensando. ¿Qué necesita realmente este juego? ¿Qué puedo recortar? ¿Cuál es la arquitectura más simple que podría funcionar?

Algunas decisiones:

Host-cliente, no servidores dedicados. No teníamos la infraestructura ni el presupuesto para servidores dedicados, y la arquitectura del juego asumía que el juego de un jugador sería autoritativo de todos modos. Host-cliente era la opción práctica.

Autoridad en el host, pero confiar en el cliente para cosas no críticas. Predicción de movimiento del jugador en el cliente, pero todas las acciones de construcción y cambios de estado persistentes validados por el host. Esto nos dio gameplay fluido sin abrir la puerta a trampas serias.

No sincronizar todo. El juego tenía miles de objetos decorativos. Sincronizar cada lámpara hundiría el ancho de banda. Identifiqué lo que realmente importaba—posiciones de jugadores, acciones de construcción, propiedad—y solo sincronicé eso.

La construcción

La implementación fue trabajo concentrado. Algunas cosas que ayudaron:

Empezar con el camino feliz. Conseguir que dos jugadores se conecten y se vean antes de preocuparse por casos límite. Las victorias tempranas importan para la moral cuando vas contrarreloj.

Probar constantemente. Tuve colegas ayudando con pruebas durante todo el proceso, no solo al final. Descubrir un fallo de diseño fundamental en la semana tres habría sido mortal.

Documentar sobre la marcha. Escribí notas sobre cada decisión. Cuando inevitablemente olvidé por qué algo estaba hecho de cierta manera, las notas estaban ahí. Esto también ayudó cuando metimos a otras personas en el sistema más tarde.

Aceptar la imperfección. Algunos casos límite no valían la pena resolver en la primera versión. Mantuve una lista de “problemas conocidos que no bloquean el lanzamiento” y seguí adelante.

Los problemas

Nada sale rodado.

Problemas de transporte de Steam. Steamworks tiene sus propias ideas sobre cómo debería funcionar el networking. Integrarlo con Netcode for GameObjects requirió entender las suposiciones de ambos sistemas sobre el ciclo de vida de la conexión, y no siempre coincidían.

Sorpresas de serialización. Parte de nuestro estado de juego no estaba diseñado pensando en serialización de red. Objetos que funcionaban bien en local fallaban al reconstruirse correctamente en el cliente. Tuve que reescribir varios caminos de serialización.

La base de código existente. El juego tenía años de suposiciones de single-player incorporadas. Algunos sistemas esperaban ser el único escritor de ciertos datos. Encontrar y arreglar estas suposiciones ocultas me llevó un tiempo que no había previsto.

Qué se publicó

Un mes después, teníamos multijugador funcionando. Los jugadores podían conectarse, verse, visitar casas y construir juntos. El sistema gestionaba desconexiones con elegancia y se recuperaba de la mayoría de estados de error.

¿Era perfecto? No. Había casos límite que conocía y probablemente algunos que no. Pero funcionaba, era estable y se publicó.

Qué aprendí

Las restricciones ayudan a ver claro. Tener un mes me obligó a tomar decisiones que de otra forma habría ido posponiendo. “No tenemos tiempo” es una razón legítima para elegir el enfoque más simple.

El networking va de trade-offs. Cada elección—modelo de autoridad, frecuencia de sincronización, qué replicar—implica sacrificar algo entre capacidad de respuesta, ancho de banda, complejidad y resistencia a trampas. No hay una respuesta universalmente correcta.

Lo difícil no es el networking en sí. El framework maneja paquetes. Lo difícil es averiguar qué necesita realmente sincronizar tu juego y cómo integrarlo con sistemas existentes que no se construyeron pensando en multijugador.

Fíate, pero comprueba. Nos fiamos de los informes de progreso de alguien y la pagamos. Ahora pido demos, no descripciones. “Enséñame que funciona” es una petición razonable.

¿Lo volvería a hacer?

Construir un sistema multijugador bajo este tipo de presión no es algo que recomendaría buscar. Pero me alegro de haberlo vivido. El deadline impuso claridad, y lanzar bajo presión me enseñó de lo que soy capaz de verdad.

La próxima vez que alguien me diga que algo es imposible en el tiempo disponible, recordaré el mes que construí multijugador desde cero. Casi siempre “imposible” solo significa “requiere enfoque.”