Cómo construí ConnectAll: un juego de puzzle para Android con Kotlin
ConnectAll es un juego de puzzle para Android con un objetivo simple: conecta todos los puntos del tablero trazando líneas sin que se crucen. Un concepto clásico con una ejecución que pone a prueba la arquitectura de la app desde el primer nivel.
En este artículo cuento cómo pasé de la idea inicial al lanzamiento en Google Play: las decisiones de arquitectura, la lógica del motor de juego en Kotlin, el sistema de niveles y cómo integré AdMob sin que arruinase la experiencia de usuario.
La idea y el prototipo
Los juegos de puzzle tienen una ventaja clara para un desarrollador en solitario: el bucle de juego es acotado y la progresión es predecible. No necesitas servidores, no hay estado en tiempo real y la retención se puede trabajar con niveles bien diseñados.
El concepto de ConnectAll es directo: un tablero NxN con pares de puntos de colores. El jugador debe unirlos con líneas que cubran todo el tablero sin cruzarse. La dificultad crece aumentando el tamaño del tablero y el número de pares.
Arquitectura: MVVM con Jetpack
Elegí la arquitectura MVVM desde el principio por dos razones: testabilidad del ViewModel y separación limpia entre la lógica del juego y la interfaz.
- GameViewModel: gestiona el estado del tablero, valida movimientos y detecta victoria o bloqueo
- BoardView: un Canvas personalizado que dibuja la cuadrícula, los puntos y las líneas activas en tiempo real
- LevelRepository: carga la definición de cada nivel desde archivos JSON en los assets, sin base de datos
Usar StateFlow del paquete kotlinx.coroutines en el ViewModel simplificó
la comunicación con la vista: cada cambio de estado del tablero se emite como un nuevo valor y
la UI reacciona automáticamente.
El motor de juego: validación de movimientos
La parte más compleja fue la lógica de validación. Cada movimiento tiene que cumplir tres condiciones:
- El trazo solo puede avanzar a celdas adyacentes (arriba, abajo, izquierda, derecha)
- No puede cruzar trazos de otro color
- Si el trazo llega al punto destino del mismo color, el camino queda bloqueado (ya no se puede modificar hasta deshacer)
Modelé el tablero como una matriz de celdas con un estado enumerado: Empty,
Dot(color) o Path(color). La validación se reduce a comprobar el estado
de la celda destino antes de aplicar el movimiento.
Decisión de diseño: Guardé cada nivel como un archivo JSON en los assets de la
app en lugar de una base de datos local. Con niveles prediseñados, no necesitas Room ni SQLite:
los archivos se empaquetan con la app y se cargan en memoria con Gson al inicio de
cada partida.
Monetización con AdMob sin dañar la UX
Integrar publicidad en un juego de puzzle requiere cuidado: un anuncio en el momento equivocado rompe la concentración y genera reseñas negativas. Decidí usar solo dos formatos:
- Banners fijos en la pantalla de selección de niveles (no durante el juego)
- Interstitials después de completar un nivel, con un retraso mínimo de 5 partidas para no saturar al jugador
La clave fue implementar un AdFrequencyManager sencillo que cuenta partidas en
SharedPreferences y solo muestra el interstitial cuando se cumple el umbral. De esta
forma, los jugadores nuevos completan varios niveles antes de ver su primer anuncio completo.
Lanzamiento en Google Play
El proceso de publicación en Google Play tiene más pasos de lo que parece la primera vez:
- Crear la ficha de Play Store con capturas de pantalla, icono, descripción corta y larga en español e inglés
- Configurar la política de privacidad (obligatoria incluso si la app no recoge datos)
- Rellenar el cuestionario de calificación de contenido (IARC)
- Subir el primer APK en modo prueba interna, validar con el propio teléfono y luego publicar en producción
El primer lanzamiento tardó unos tres días en ser revisado. A partir del segundo update, las revisiones se resuelven en horas.
Lecciones aprendidas
- Diseñar los primeros niveles es más difícil que programar el motor: si el jugador se traba demasiado pronto, no llega a ver los niveles complejos
- El Canvas personalizado de Android es potente pero verboso; en un proyecto nuevo usaría
Jetpack Compose con un
DrawScopepara reducir código - AdMob requiere paciencia para calibrar la frecuencia: empieza con un umbral alto (más partidas entre anuncios) y ajusta según los datos de retención
- Las capturas de pantalla de la Play Store son la primera impresión del juego: merece la pena invertir tiempo en hacerlas con dispositivos reales o un emulador a alta resolución
Prueba ConnectAll en Google Play
Descarga el juego, empieza con los niveles fáciles y sube hasta los más complejos.