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

No hay comentarios: