27 de mayo de 2011

T-Shirt Litiopixel modelo 2


Nueva camiseta del proyecto... hay que estar guapo para recibir a las visitas... ;D

Mini KDD en Barcelona...


He quedado con mi amiguete Javier (socio mío en el difunto proyecto Monkeydreams.net, ver sección Abandonware) que viaja desde Valencia a pasar el fin de semana.

Obligada charla geek y muestra de la evolución del proyecto en el iPad...

Y como no, aprovecharemos para dar una vuelta por la Apple Center de la Maquinista, a ver qué tal...

Versión test para GP2X / WIZ


He preparado una versión especial para GP2X y WIZ. He reducido todos gráficos del fondo a un ancho de 320 píxels para reducir la carga de memoria. Aún así el 90% de los gráficos son los originales para iPad.


El juego funciona perfectamente, aunque tiene un fallo de flickering (parpadeo de pantalla) bastante notable. Sólo he adaptado la ventana de render a 320x240, el resto del código es el mismo y por tanto los cálculos de reloj y frames están pensados para una máquina más potente.

ACTUALIZACIÓN: Javier ha probado el código en WIZ y no funciona. ¿Alguna pista?

24 de mayo de 2011

Test Movimiento y control de objetos 2

Segundo test de control de movimiento e interactividad con los objetos del mapa. Recomendada reproducción a 720p.


NOTA: La velocidad de reproducción no corresponde con la realidad ya que la herramienta para capturar vídeo más luego una conversión compatible con Youtube ralentiza el vídeo.

23 de mayo de 2011

Grabador / reproductor de acciones


He desarrollado una sencilla función destinada a implementar como IA a los bot que voy a utilizar en el juego. Almaceno en una matriz una serie de acciones que se reproducen de forma encadenada cuando "la situación de la historia" llega a un punto concreto.

Ideal para representar escenas, acciones automáticas e incluso lo puedo emplear si lo veo necesario a modo de tutorial.

18 de mayo de 2011

Mapas con persistencia

Estoy creando ya algunos mapas. Para el juego, he pensado en definir un mapa por habitación/zona en lugar de declarar un mapa gigantesco delimitado por zonas.

La ventaja de utilizar mapas reducidos frente a enormes matrices es que de esta forma me permite cargarlos rápidamente. La gestión de objetos y eventos la realizo por cada zona... hay muchas variables que se mantienen constantes por mucho que se cambie de mapa, como por ejemplo la luz global.

Lo más complicado es mantener una coherencia con el entorno. Una puerta que se abre en cierta zona, debe permanecer abierta hasta que se cierre, por mucho que cambiemos de habitación. Esto me obliga a almacenar el estado de un mapa cuando el jugador pasa a otra sala.

Finalmente lo he solventado almacenando en el disco un fichero backup.x por cada zona que se visita (x es el número que corresponde al mapa).

Cuando el jugador vuelve a un mapa que ya se ha visitado, recupero el fichero backup correspondiente, ya que contiene el estado de items/traps que anteriormente he guardado.

16 de mayo de 2011

Dos tipos de movimiento


He incluído dos tipos de movimiento de mapa con respecto al personaje principal. Por una parte tenemos que el que se mueve es el protagonista (captura de pantalla izquierda) y por la otra parte (derecha), que el que se mueve es el mapa, quedando el personaje principal siempre en la misma posición.

En función del tipo de mapa seleccionaré un movimiento u otro.

14 de mayo de 2011

Vamos que nos vamos!!!

Ya! Por fin! rutina TouchControl finalizada por fin, así que... PODEMOS AVANZAR! ...esta vez de verdad ;)

El blog se estaba convirtiendo casi en un monólogo sobre el tema del control de pantalla. Rutina reescrita hasta la saciedad y probada en inumerables pruebas...

Creo que ya está terminada, no la toco más... Amigos que han probado el programa también lo confirman así que la doy por cerrada. Gracias por probar la app!!!! ;)

Creo que con esto de "retocar y retocar y retocar el código" he aprendido a no obsesionarme y centrarme en una sola rutina, sobretodo si se trabaja solo como es mi caso. Quizás he dedicado demasiado tiempo desarrollando en exceso una función que ya funcionaba correctamente en versiones anteriores... hmmm.

13 de mayo de 2011

Un mundo en "capas"

He organizado mi mundo por capas. Cada capa está alojada en una matriz. Cada matriz es diferente dependiendo de la cantidad de contenido a almacenar. Veamos cómo se me ha ocurrido organizar todo esto.


He creado varias matrices que contienen todos los datos referentes al mapa; suelos, objetos, triggers, etc. Cada capa tiene un tamaño diferente para así poder acceder más rápidamente a datos específicos de cada ítem.

MAPA_Matriz_Graficos%[] Contiene los datos de los gráficos del decorado.
MAPA_Matriz_Bloqueos%[] Capa obstáculos. (Muros).
ITEMS_Mapa[] Matriz lineal cantidad n de objetos.
TRAP_Mapa[] Matriz lineal triggers.

Primero cargo la matriz principal MAPA_Matriz_Graficos%[], empleando el típico bluce:

FUNCTION Carga_Datos_Mapa:
  LOCAL Disco=OPENFILE(1,MAPA_Fichero_Matriz_Graficos$,TRUE)
    IF (Disco)
      FOR Contador_Temp_Y=0 TO MAPA_Tamano_Alto-1
        FOR Contador_Temp_X=0 TO MAPA_Tamano_Ancho-1
          READBYTE 1,MAPA_Matriz_Graficos[Contador_Temp_X][Contador_Temp_Y]
        NEXT
      NEXT
      CLOSEFILE 1
    ENDIF
ENDFUNCTION

Es necesario también definir los muros del mapa:

REDIM MAPA_Matriz_Bloqueos[0][0]
REDIM MAPA_Matriz_Bloqueos[MAPA_Tamano_Ancho][MAPA_Tamano_Alto]
RESTORE LISTADO_DATOS_MAPA_0_BLOQUEOS

LOCAL Dato$
FOR m=0 TO MAPA_Tamano_Alto-1
  READ Dato$
  FOR n=0 TO MAPA_Tamano_Ancho-1
    MAPA_Matriz_Bloqueos[n][m]=MID$(Dato$,n,1)
  NEXT
NEXT

STARTDATA LISTADO_DATOS_MAPA_0_BLOQUEOS:
  DATA "0000000"
  DATA "0001000"
  DATA "0001000"
  DATA "0011100"
  DATA "0011100"
  DATA "0011100"
  DATA "0011100"
  DATA "0011100"
  DATA "0011100"
  DATA "0011100"
  DATA "0001000"
  DATA "0001000"
  DATA "0000000"
ENDDATA

A continuación cargo todos los datos referentes a los objetos y triggers:

ITEMS_Cantidad=9
REDIM ITEMS_Mapa[0]
REDIM ITEMS_Mapa[ITEMS_Cantidad]

RESTORE LISTADO_OBJETOS_MAPA_0

FOR n=0 TO ITEMS_Cantidad-1
  READ ITEMS_Mapa[n].PosX
  READ ITEMS_Mapa[n].PosY
  READ ITEMS_Mapa[n].Grafico
  READ ITEMS_Mapa[n].Evento
  READ ITEMS_Mapa[n].Activado
  READ ITEMS_Mapa[n].Tipo
  READ ITEMS_Mapa[n].DatoExtra
  READ ITEMS_Mapa[n].DatoExtra_B
NEXT

STARTDATA LISTADO_OBJETOS_MAPA_0:
  DATA 3,4,2,2,0,1,0,0
  DATA 3,1,4,4,0,1,3,1
  DATA 3,2,3,3,0,1,3,1
  DATA 3,6,2,5,0,1,2,0
  DATA 2,3,8,7,0,0,0,0
  DATA 3,10,4,0,0,1,0,0
  DATA 3,11,3,0,0,1,0,0
  DATA 4,4,8,7,0,0,0,0
  DATA 4,6,8,7,0,0,0,0
ENDDATA

TRAP_Cantidad=4
REDIM TRAP_Mapa[0]
REDIM TRAP_Mapa[TRAP_Cantidad]

RESTORE LISTADO_TRAPS_MAPA_0

FOR n=0 TO TRAP_Cantidad-1
  READ TRAP_Mapa[n].PosX
  READ TRAP_Mapa[n].PosY
  READ TRAP_Mapa[n].Salto_Mapa
  READ TRAP_Mapa[n].Salto_PosX
  READ TRAP_Mapa[n].Salto_PosY
  READ TRAP_Mapa[n].Direccion_Vista
  READ TRAP_Mapa[n].Activado
  READ TRAP_Mapa[n].Tipo
  READ TRAP_Mapa[n].Grafico
NEXT

STARTDATA LISTADO_TRAPS_MAPA_0:
  DATA 3,7,0,0,0,0,1,1,16
  DATA 2,4,0,0,0,0,1,2,17
  DATA 2,8,0,4,2,0,1,3,18
  DATA 4,2,0,2,8,0,1,3,18
ENDDATA

El porqué de cargar todos los datos por separado es principalmente por la necesidad de almacenar más de un valor en una posición del mapa XY.

Inicialmente pensé en realizar una matriz bidimensional  y que con diferentes valores ya se definirían los ítems y cómo interactuar con ellos. Más tarde se me ocurrió que un mismo objeto no tenía porqué reaccionar siempre igual. Un botón en el mapa realiza siempre la misma acción (visual), pero en cambio puede "realizar" acciones diferentes (encender la luz, abrir una puerta, etc). decidí hacerlos "programables".

Pensando en alguna forma de almacenar más de un dato en una posición determinada del mapa llegué a lo siguiente...

Como ya se ha visto, cargo los datos referentes a los muros en una matriz bidimensional que corresponde al ancho y alto del mapa. Luego cargo los datos de los objetos y también los triggers en una matriz lineal sobre un objeto definido por TYPE, tal como se ve en el código.

Los objetos que son NO movibles ni recogibles son insertados en la matriz principal y me olvido de ellos, puesto que se comportan como muros a nivel del Algoritmo A* aunque siguen puediendo provocar eventos.

A todos los objetos se les puede asignar una acción (evento) que se declara también. El mismo método es el empleado para los triggers pero a diferencia de los objetos, son invisibles y SIEMPRE traspasables por el jugador.

Cuando el personaje encuentra una posición del mapa que contiene un objeto, un trigger ó ambos, se recorre la matriz lineal del objeto/trigger para localizar el ítem en cuestión y cómo ha sido programado éste. Si se ha definido un evento se ejecuta, en caso contrario se devuelve el control al jugador.

Finalmente señalar que de esta forma consigo dos cosas: la matriz de objetos es más pequeña por lo que consume menos memoria siendo más rápido su acceso y por otra parte poder almacenar hasta 7 variables en una posición XY del mapa.

Supongo que se ha entendido... :-P

11 de mayo de 2011

Presentando progresos...

15 días sin publicar ningún avance en el blog...

Como ya comenté en el post anterior, he estado trabajando en la sombra y es hora de hacer públicos los avances de tanto trabajo oculto. (Nota mental para mí: modificar hoja de ruta ;))

En la última publicación del blog estaba en la versión 04a y actualmente ya he avanzado hasta la actual número 23 (la anterior, 22Clean es la última cargadita de líneas REM sin "limpiar").


Tanto número de versión puede parecer muy liante, pero encuentro que es una forma de tener organizado todo el desarrollo del proyecto. En lugar de andar con SVN y similares, realizo manualmente la copia del proyecto cada día en una carpeta que luego guardaré en un DVD (o dos).

El proyecto está muy avanzado. He reescrito mucha parte del código y también he modificado algunas rutinas sobre las que no estaba muy satisfecho. La rutina de ControlTouch (encargada de gestionar DÓNDE y QUÉ hacer al pulsar en pantalla) la he vuelto a desarrollar desde cero y no he parado de probarla hasta la saciedad.

La definición del "mundo" y los mapas ha sufrido alguna que otra variación. Es un tema que dejo pendiente para una posterior publicación en el blog, ya que me gustaría explicar cómo he diseñado toda esta parte.

La animación del personaje así como su interacción con el "mundo" también ha sido modificada; actualmente el protagonista puede detectar que tipo de objeto ha tocado y consecuentemente realizar la acción que corresponda. También detecta si hay objetos recogibles, traspasables, etc...

Ah! Y he añadido un trigger para teletransportación... :D