Web Analytics

Turnos NOSECUANTOS

Ay...

Vengo de dar un paseo a ver si aclaro las ideas y por ahí siguen emborronanding la mente de este pobre, pobre mortal. Tengo la cabeza llena de pájaros sobre plugins, bases de datos y chominadas tan variopintas que pueden dar a esto un toque tan chulísimo que ahora me pierdo con lo básico: El controlador de los cojones.

El controlador de los cojones debería recibir eventos concretos y finitos del tipo click, drag, doubleClick, longClick y cosuelas por el estilo.... A ver si escribiending un poco me aclaro yo mismo, que esto me trae jodidamente liado con respecto a lo que había pensado antes.

Tal como lo presento ahora, el controlador deberá hacer eso, recibir los eventos de usuario y poco más. Quizá también recibir los eventos de la red o lo que sea que vaya añadiendo como temporizadores para las animaciones, etc. Pongamos que sea eso y sólo eso.

El controlador de los cojones (a partir de ahora, el controlador o controller), será una clase que instanciará el framework. No me queda claro que tenga que ser reimplementado por cada juego ni mucho menos. Es por esto que me paré a pensar y llevo una hora con pico largo tocándome los güevos a fuerza de pajas mentales al respecto de qué cojones hacer con ello.

Vamos a suponer que se instancia y es dependiente del juego a implementar. Por aquello de, qué se yo, que cada cual quiera montar el suyo propio. Hay gente muy rara. Si hago eso, no tiene sentido la delegación de responsabilidades cuando el usuario programador se va a ahorrar todas mis pajas mentales sobre separar capas metiendo todo en la misma.

Vale bien. Pues que no, vamos, que no se instancia y punto. ¡Fijamos el controlador!

Con el controlador fijado tenemos que responder al menos a:
click(view) ¿sobra?
click(view, x, y)
longClick(view, x, y)
drag(view, x, y, x1, y1) --> ¿startDrag stopDrag?

El controlador no debería saber nada sobre la lógica propia del sistema destino como, por ejemplo, cuando el usuario hace scroll. El scroll en un móvil no es un drag... Sí es un drag, pero habría que distinguirlo del gesto para mover el mapa. El drag sería más un longClick+drag. Da que pensar eso... Quizá sobre algún evento pero el meollo no es este. El meollo es procesar un click.

Si fijamos el controlador, tendrá que haber unos comandos predeterminados y ya la estamos jodiendo más de lo que esperaba. Ya estoy separando en clases la implementación de los comandos como la otra vez. La gestión de errores se convierte en una horrible proliferación de try catch y handlers absurdos. ay madre... ay madre... nuevas instancias y paridas varias. Cagonlaputa. Cagonlaputa...

Pero vamos a tirar por aquí que es por donde nos mandan los buenos haceres de esto de programar. Pondremos una clase abstracta para los comandos y un adapter para el que quiera sólo implementar un método. El controlador debería buscar por nombre un comando, instanciar la clase y cachear la instancia para no tener que volver a crear otra en la siguiente ejecución.

Echamos un ojo a la interfaz del comando:
[CommandName]Command <> (
setController(owner);
execute(Model)::Forward;
canExecute(Model)::boolean;
canUndo(Model)::boolean;
undo(Model)::Forward;
)

Un posible adapter sería el que devuelva en canUndo false, en el Undo no haga nada y en el canExecute un true como una casa. En el Execute debería lanzar una excepción "Not implemented!". Eso quita errores de compilación pero sabes lo que no está hecho porque no te da un nullpointer pero avisa... Ya lo hice más veces y se muestra bastante efectiva la cosa (a los clientes no les gusta).

Bien... Bien... ¡tresbien!

Emh... A ver cómo cojones nos libramos de reimplementar el controlador.

Tengo por ahí definido eso del forward. Eso del Forward es más bien un tipo de retorno, no es un action-forward del estilo de los que ya conocemos por ahí. Lo he pensado como algo con lo que controlar al controlador como el action-forward pero indicando si seguir la ejecución o no, mientras que la siguiente acción a ejecutar se guardará en el modelo. Hay que recordar que lo que queremos es poder enviar la ristra de "acciones" a ejecutar a otro cliente que pueda reproducir los pasos dados por este u otros usuarios en un momento dado. Además queremos poder deshacer (undo) o restaurar el estado de edición en cualquier momento después de un evento hardware de cualquier dispositivo. Las acciones se apilan. No se apilan sus resultados pero sí las acciones y sus entradas.

Recordamos en capítulos anteriores (toca flashback), se almacenará en un metadata la entrada a cada acción y, este metadata pasará a una pila. Tras terminar una acción se apilará esa llamada y se pasará a la siguiente. La siguiente acción a ejecutar se dejaría en la cima de la pila con un metadata nuevo. Creo que ya me voy aclaranding. A ver cómo queda lo del click:
click!!!
controlador, carajo, llega un click en el pixel XY del mapa
modifica el metadata (cima de la pila que está vacía, así que ejecuta un push) dejando X, Y, "Map", Click
y lanza la ejecución del comando
la clase es ClickCommand

---> ClickCommand.canExecute():: true
---> ClickCommand.execute()!!!!!!!!
en el execute, ya sabemos x, y, convertimos a coordenadas del mundo y  hacemos un push
model.push(tileX tileY, map, ClickMap)
devolvemos ActionResult.CONTINUE

---> ClickMap.canExecute()::true
---> ClickMap.execute()!!!! ^g^
en el execute sabemos ya el tile y si hay un algo q seleccionar. Si no hay nada que seleccionar, limpiamos la pila y devolvemos Action.STOP, el click no sirvió de nada
Si hay una ficha, la buscamos, la añadimos a la pila y lanzamos la acción que la selecciona...

Esa última acción que selecciona la ficha, sería de esas que maneja las vistas, donde entra aquella interfaz chula que tengo que repensar otra vez.

Por otra parte, la primera acción también hará uso de esa interfaz ya que tiene que convertir de coordenadas de pantalla a coordenadas del mundo. con la iglesia hemos dado.

Eso otro día. Voy a ver si medio programo la jerarquía de comandos que quiero verlos funcionar...