Monday, February 25, 2019

Mientras tanto, en Plutón...

Sé que la última vez dije que en la siguiente entrada hablaríamos de la definición de objetos, pero he decidido cambiar ligeramente la ruta y hablar de la definición de los flags, de modo que cuando hablemos de los objetos y las acciones tengamos toda la información disponible.

Banderas de nuestros parsers

Los flags se definen en el archivo flags.json y permiten definir un valor booleano o entero que puede ser -y será- consultado desde otras partes de la aventura.

Por ejemplo, en el actual estado de La Aventura Original sólo hay un flag:

{
  "id":1,
  "name":"Pila en linterna",
  "type":1,
  "booleanValue":"false",
  "integerValue":null
}

Como habrán supuesto, es un flag que indica si el jugador ha metido o no la pila en la linterna. Esto permite desbloquear determinadas acciones, como encender y apagar la linterna o meter y sacar la pila. Al intentar realizar estas acciones el motor comprueba el valor del flag y permite o bloquea la ejecución de la acción en consecuencia.

El contenido de la clase GameFlag es bastante simple, con un identificador único para cada flag, un nombre descriptivo para facilitar su manejo por parte del diseñador/programador, un identificador de tipo (con valor 1 en este caso para identificarlo como booleano) y dos campos con el valor del flag, booleanValue para los flags booleanos e integerValue para los flags de tipo entero.

Y, ahora sí, nos vemos en la próxima entrada con la definición de objetos.

Thursday, February 21, 2019

La Navidad no se acaba hasta que lo dice el Arzobispo de Estrasburgo

Hace poco estuve en Estrasburgo visitando a unos amigos. Mi intención original era ir en diciembre para poder ver los mundialmente famosos mercados navideños de la zona, pero no pude ir porque en ese momento ellos iban a estar de viaje. Me quedé sin mercadillo pero me libré de los atentados, creo que salí ganando.

El caso es que por esa zona se toman la Navidad muy a pecho, tan a pecho que en la catedral todavía tenían puesto el Belén.


Bueno, es eso o la típica pereza que te lleva a tener los adornos puestos unos días de más pero llevada al extremo.

Monday, February 18, 2019

Mientras tanto, en Plutón...

Terminamos la comparación entre la definición de las localizaciones en las dos versiones del motor dándole un vistazo rápido al resto de cosas que se han añadido en la versión 1.0 y siguientes.

Esta ni siquiera es mi forma final

La lista se encuentra, por cierto, en plena mutación debido a que hay cosas que aun no están implementadas y otras que tienen los días contados al ser vestigios de la implementación inicial de algunas funcionalidades.

  • light. El valor de iluminación "natural" de la localización. Con el desarrollo de las fuentes de luz este atributo ha quedado obsoleto.
  • defaultImageResource. Otro atributo obsoleto de tiempos más sencillos anteriores a la llegada de las fuentes de luz.
  • exterior. Atributo lógico que indica si la localización es interior o exterior. El efecto que tendrá esto en el jugador y qué hace que una localización sea interior o exterior depende en gran medida del diseñador de la aventura. En Pluto Crash, por ejemplo, el personaje muere si entra en una localización exterior sin haber cogido antes el traje espacial.
  • onEnterTriggers. Disparadores que se activarán cuando un personaje entre en la localización. Los disparadores son una cosa bastante compleja que analizaremos más adelante. No, en serio, cuando lleguemos a ellos me agradecerán que no me halla liado con ellos ahora.
  • onExitTriggers. Disparadores que se activarán cuando un personaje salga de una habitación.
  • onGeneralActionTriggers, onActionTriggers. Pendiente de implementación. Serán los disparadores que se activarán cuando un personaje lleve a cabo una determinada acción en una localización. Hasta ahora las acciones del jugador sólo tienen disparadores asociados definidos en los objetos o los personajes sobre los que actúa, estos disparadores darán más flexibilidad a la hora de definir la respuesta del entorno a las acciones del jugador.
  • onLightChangeTriggers. Pendiente de implementación. Disparadores que reaccionarán al añadir o sustraer una fuente de luz. Como si la iluminación no fuese ya bastante complicada.
  • locationEffects. Pendiente de implementación pero con bastantes papeletas para desaparecer. Define los efectos -de los que no hablaremos ahora porque los efectos están muy relacionados con los disparadores y será mejor tratarlos a la vez- que se ejecutan mientras el personaje se encuentre en la localización. En cierto modo se solapa con los efectos disparados por los onEnterTriggers, al poderse poner en marcha efectos cuando el personaje entre en la localización que se detengan mediante un disparador definido en onExitTriggers.

Pues hasta aquí las localizaciones, permanezcan en sintonía para saber cómo ha cambiado la definición de objetos y averiguar qué fue de la definición de acciones.

Sunday, February 17, 2019

Mientras tanto, en Plutón...

Seguimos analizando las diferencias en la definición de localizaciones entre la versión primitiva del motor y la actual. Hoy toca el movimiento entre localizaciones... y la muerte.

Por donde he venido, me voy

En la versión anterior cada dirección de movimiento se definía mediante una etiqueta propia, siendo el valor dentro de la misma el identificador de la localización a la que se moverá el personaje si se mueve en esa dirección o 0 si no hay movimiento posible en esa dirección.

    <location>
        ...
        <north>4</north>
        <south>11</south>
        <east>0</east>
        <west>0</west>
        <northeast>0</northeast>
        <northwest>0</northwest>
        <southeast>19</southeast>
        <southwest>0</southwest>
        <enter>2</enter>
        <exit>0</exit>
        <up>0</up>
        <down>0</down>
    </location>


En la versión actual las direcciones de movimiento posibles se definen dentro del array exits, en el que sólo aparecerán las direcciones de movimiento que lleven a una localización.

  {
    "id":1,
    "name":"Granja",
    ...
    "exits":[
      {
        "direction":1,
        "destination":4,
        "description":""
      },
      {
        "direction":2,
        "destination":11,
        "description":""
      },
      {
        "direction":7,
        "destination":19,
        "description":""
      },
      {
        "direction":9,
        "destination":2,
        "description":""
      }
    ],
    ...
  }


Como se puede ver dentro de exits hay una serie de objetos que representan las posibles direcciones de movimiento. El atributo direction contiene el identificador correspondiente a la dirección -definido como un valor constante en las clases de configuración del motor-, el atributo destination contiene el identificador de la localización a la que se moverá el personaje y el atributo description contendrá el texto que se mostrará cuando el jugador ejecute la acción "mirar" en esa dirección cuando me ponga a implementarlo, claro. Sí, en estos artículos vamos a encontrarnos con unas cosas que no están ni siquiera a medio cocer.

En ambos casos si el valor de destination es negativo quiere decir que el personaje morirá al moverse en esa dirección -en La Aventura Original esto ocurre si el jugador se mueve dentro del volcán o en la dirección en la que se encuentran los dos barrancos. Sí, esto no es del todo justo y ese es uno de los motivos por los que quería implementar la descripción de la dirección de movimiento, para dar la opción de avisar al jugador de lo que puede pasar si se mueve en esa dirección-. Aunque esto no es del todo cierto, ya que lo que en un principio estaba pensado para las pantallas de muerte del personaje se ha acabado utilizando también para las pantallas de fin de juego. Ya hablaremos de eso cuando le toque la hora al archivo death_infos.json.

El movimiento no tiene mucho más que explicar. Cuando el jugador ejecuta una instrucción de movimiento -como "norte", "sur" o "bajar"- el parser busca el identificador asociado con esa dirección y busca dentro de exits un objeto con esa dirección en su atributo direction. Si lo encuentra se mueve al personaje a la localización especificada en destination o muestra un mensaje de error predefinido si no existe esa dirección de movimiento en la localización actual.

Mucho más sencillo que lo de las fuentes de iluminación ¿Verdad?

Wednesday, February 13, 2019

Mientras tanto, en Plutón...

Como decíamos ayer, vamos a echarle un vistazo a las diferencias entre las descripciones de las localizaciones en la versión primitiva del motor y la flamante actual versión 1.2.

Hágase la luz

La primera diferencia relevante es la definición de la descripción y la imagen de la localización, fijadas en las etiquetas description e image en el XML y en un array en la etiqueta descriptions en el JSON.
En la nueva versión se permite definir una serie de descripciones diferentes que se mostrarán en función del tipo de iluminación activa en la localización. En el ejemplo de La Aventura Orignal sólo se puede ver una descripción para cada localización, pero este ejemplo de Pluto Crash servirá mejor para ilustrar cómo funciona todo esto:

"descriptions":[
      {
        "id":1,
        "lightSource":0,
        "description":"No puedes ver nada con
la escasa luz que llega desde el pasillo.
Al moverte puedes notar cómo chapoteas en
un líquido que no debería estar aquí.",
        "locationImage":"loc_010.png"
      },
      {
        "id":2,
        "lightSource":2,
        "description":"Las paredes del pozo de
mantenimiento están cubiertas de tuberías y gruesos
cables. El suelo está cubierto de fluido hidráulico.",
        "locationImage":"loc_010_02.png"
      }
    ]


En este caso se proporcionan dos descripciones diferentes, una para dos valores de iluminación diferentes. En el primer elemento del array se pueden ver los valores que se usarán cuando el usuario se encuentre en la localización sin una fuente de luz propia -valor lightSource 0, correspondiente a oscuridad total- o con una fuente de luz artificial -valor lightSource 2-.

En el ejemplo de La Aventura Original podemos ver que ambas localizaciones tienen una fuente de luz con un lightValue de 6, que corresponde a la luz natural diurna y normalmente tiene preferencia sobre el resto de fuentes de iluminación.

"lightSources":[
      {
        "id":1,
        "sourceId":-1,
        "lightValue":6
      }
    ]


Normalmente las localizaciones sólo cuentan con una fuente de luz, la de la propia localización. Sin embargo, es posible que el personaje o un efecto dejen en una localización un objeto que emita luz; en este caso se añadirá a las fuentes de luz de la localización una fuente de luz adicional correspondiente al objeto. En este caso la nueva fuente de luz tendrá un valor de -2 en el atributo sourceId, frente al valor -1 correspondiente a las fuentes de luz propias de la localización.

Así, al entrar en una localización el motor compara las fuentes de luz presentes en la localización -las fuentes de luz definidas en la propia localización y la mejor fuente de luz emitida por los objetos del inventario del personaje-, quedándose con la que tenga el valor lightValue más alto y usará la descripción con un valor lightSource igual, o la descripción con el valor lightSource más alto si todos son menores que la fuente de luz actual.

La cosa se ha hecho un poco larga así que seguiremos con el resto de diferencias en la próxima entrada. Ale, a programar.