Otra jodienda a la lista: las coordenadas del mundo.
Podemos suponer dehecho el nudo gordiano ese de la gestión de eventos con los managers y el controlador... También la ejecución de turnos complejos guardando una especie de metadata en el modelo sobre el que poder ejecutar condiciones etc. Bueno, ahora a ver cómo se enlaza esto con la vista.
En el diagrama anterior tenía cosas por ahí del tipo "updateView()" o cosa tal. Vale para un esbozo preliminar. En realidad antes de llegar a un diseñó potable, esas cosas están bien. Lo mismo tengo con el click() pero ese click puede ser un drag-drop o la virgen maría. Faltaría detallar el resto de métodos pero la comunicación parece haber quedado suficientemente clara.
El problema está en tener un manager que se encarga de saber cómo manejar las vistas. Uno, varios o lo que sea, pero que no sepa lo que tiene detrás. Si añado otra capa para aislar estoy metiendo una complejidad indebida al sistema. No olvidemos que la idea final es soltarlo en un móvil.
Estoy pensando ahora mismo en tomar cuatro reglas básicas que se puedan extrapolar de unos cuantos juegos y montarme una especie de máquina virtual sobre la que poder ejecutar los juegos. Es una idea. La cosa andaría por tener una interfaz GameView que soporte añadir, eliminar, desplazar entidades. De esta manera podría tener una implementación de sólo texto o una gráfica en swing para depurar el juego (el negocio del juego) sin tener que pasar por Android. Podría entonces soltar un jar con el juego y ejecutarlo en varios entornos: texto, swing, android.
La otra alternativa es encerrar toda la lógica en el manager sin respetar una tercera capa. El manager debería encargarse de convertir las entidades del modelo a las de la vista, conservar estas referencias y actualizarlas. Esto sería más lioso de programar y mantener pero iría finísimo. Eso si, me pega la implementación de las vistas con las de la lógica que las ejecuta.
Habrá que decidirse. Parece mejor pensado lo de la tercera capa. La tercera vía. La jodienda. Es más código durante el primer desarrollo pero puede que los siguientes (que los habrá) no sean tan dolorosos.
De todas formas, el primer desarrollo será un cuatro en ralla o algo parecido. Nos meteremos con ajedrez, damas, etc. Cuando toque. Primero hay que ver que la arquitectura furrula. Luego veremos.
Tomemos cuatro juegos dispares y a ver qué carajo hay que hacer con las vistas. Además hay más de un tipo de vista dado que los menús no serán una vista del juego propiamente dicha. Supongo que se podrá hacer todo esto sin perder cierta generalización de componentes.
Primero necesitaríamos una clase que haga las veces de factoría de vistas. Es necesario mostrar y ocultar las vistas, escuchar los cambios de estado. Un ejemplo de todo eso es un diálogo. En un diálogo habrá que poner una información y habrá que saber qué ha introducido el usuario así como si ya ha pulsado el botón de cerrar, salvar, cancelar. Al mostrar, p.ej. en el Colonization el resultado de un combate, cuando el usuario cancela o acepta el diálogo podría estar ejecutándose el turno de otro jugador y debería seguir la ejecución hasta que termine. Ademas hay diálogos de los que dependen sus propias acciones: si una unidad llega cansada (3 turnos seguidos de movimiento) y ataca, se pregunta al usuario si quiere reposar o atacar. Las unidades cansadas tienen menos fuerza de ataque.
Tomemos 4 juegos, decía: damas (valdría el ajedrez también), cuatro en raya, tute y Colonization (o Advance Wars). A ver qué podemos entresacar de lo que debería poder hacer la interfaz de usuario en cuanto toca a animaciones y toda esta pesca:
TileMap:
Crear un mapa
añadir capa
modificar el tilexy de la capa z
animar tiles
scroll inmediato
scroll animado
cada tile tiene que tener referencia o relación rápida con parte del modelo.
cada capa "
cada mapa "
Sprites
crear
transformar
mover
animar
eliminar
un sprite debe tener relación rápida con la referencia que lo implementa en el modelo
Vistas (menú o barra de botones, vista de juego, ¿hud quizá?)
mostrar
ocultar/destruir
recuperar una vista por nombre
Dentro de las vistas habría menús o barras de botones
añadir
mostrar/ocultar
activar/desactivar
Dentro de las vistas habría vistas de juego a las que aplica lo de las capas y sprites que dije antes
Entiendo que las operaciones deberían ser transparentes al usuario, quiero decir, transparentes al manager que las llame. El manager del juego sólo debería aplicar su lógica de negocio del tipo: moverSprite(miEntidad, toX, toY). Todo lo más habrá pedido las coordenadas del mundo a la vista. El manager se quedaría esperando a una notificación porque implementará un SpriteAnimationListener o algo del tipo parecido a eso de forma que cuando el sprite haya concluido su animación, se enterará y podrá hacer desaparecer al peón que el caballo acaba de comerse. Nótese que el modelo ya estaría actualizado sin el peón antes de la ejecución de la animación.
Podríamos pensar en ordenar la ejecución de lógicas de negocio y de animaciones de forma que no sean siempre las lógicas de negocio las primeras en ejecutarse como se vió en el gráfico anterior.
Voy a echar una pensada a eso. Además las animaciones correrán en otra hebra de forma que todas las llamadas a la nueva capa sean síncronas pero devuelvan el control inmediatamente para poder devolver la hebra "swing" inmediatamente. De no ser así provocaríamos un force-close porque el sistema creerá que la aplicación se ha colgado.
El UIManager deberá ser una máquina de estados http://en.wikipedia.org/wiki/State_pattern almacenando su estado en alguna parte del modelo. También podemos pensar en http://en.wikipedia.org/wiki/Strategy_pattern. En cualquier caso deberá consultar el estado del modelo (es el estado de la UI en realidad) antes de realizar cualquier acción. No sería la mismita implementación que explican sino que habrá una acción a ejecutar y un estado almacenado en alguna parte para evitar nuevas instancias. En realidad, el llamarlos acciones sería lo correcto ya que serán nombradas de alguna manera (quizá un string) y se decidirá qué acción ejecutar dependiendo de este nombre y del estado interno. Quizá esto debería formar parte del framework aunque habría que buscar la forma de hacer que no sea necesario configurarlo: El manager tendría unos métodos a ejecutar en cada estado. Aunque, viéndolo mejor, con poner un switch gordo, quizá acabemos antes y no dejemos tonterías al framework. Eso sí, quizá sea mejor fijar qué propiedad del modelo da el paso actual del turno y cuál otra sea el estado de la UI.
Se complica la cosa porque la UI puede ser un diálogo que no es propiamente la UI. Habría que mirar la forma de fijar toda la pesca. En Android tenemos que se puede escuchar cuándo se crea o destruye un diálogo. Quizá sería bueno tener un Activity que fije todos los eventos para saber cuándo el usuario está viendo qué.
Sumo y sigo.