![]() |
![]() |
![]() |
Por dónde empezar. |
Evidentemente, antes de nada, tienes que asegurarte de disponer de todos los ingredientes necesarios para la programación con Inform. Asegurate de tener la última versión de todo, para poder seguir este cursillo. Si no sabes lo que necesitas, mira este enlace. Incluso si lo sabes, se recomienda mirarlo, pues se explica además cómo se usan estos ingredientes para "compilar" un juego, algo que tendrás que hacer muy a menudo a lo largo de este cursillo.
Ahora podemos empezar a diseñar el juego. Lo primero, evidentemente, es el guión, que puede ser una idea genérica que se vaya concretando a medida que se programa, o puede ser una historia totalmente detallada, incluyendo incluso los rompecabezas del juego. Cada uno tiene su estilo a la hora de diseñar el guión, pero en este cursillo te lo vamos a dar ya diseñado y con bastante detalle, para que sepas lo que te espera.
Estás encerrado en una torre, de la que tienes que escapar. El mapa de la torre es el siguiente, las flechas dobles quieren decir "subir o bajar".
El juego comienza en la habitación llamada PuertaPrincipal
,
pero no
se puede salir de la torre desde ahi. La salida de la torre está
en la
Mazmorra
. Para salir, el jugador deberá:
Dormitorio
, para descubrir
unas fundas atadas con correas.
Antes de lanzarnos a programar todo esto, debemos asentar claramente los principios de programación bajo Inform, que son bien distintos de los de PAWS, por esto iremos muy, muy despacio. No te impacientes, ¡todo llegará!
Lo siguiente es el esquema básico que debe seguir todo juego Inform. Más adelante iremos rellenando el esquema. Abre un nuevo fichero en tu editor favorito, como si es el Notepad de Windows o el mítico vi/m de Unix.
Constant Story "La Torre"; Constant Headline "^(c) 2000 Zak y Carlos^"; Include "Parser"; ! Aqui iría la definición de mensajes de librería. Include "Verblib"; ! Aqui irian las definiciones de las localidades ! y los objetos del juego [ Initialise ; ]; Include "SpanishG"; ! Aqui irían los verbos y acciones específicas de nuestro juego. |
Copialo todo tal cual, especialmente pon cuidado en los punto y coma. Aunque parezca increible, eso ya es un programa completo en Inform, puedes compilarlo y tratar de jugarlo con el comando 'inform fichero.inf' y jugarlo con "frotz fichero.z5' o abriéndo el fichero Z5 en WinFrotz. . Naturalmente no podrás hacer gran cosa, ya que no hay localidades ni objetos. Aún así, puedes intentar una gran variedad de acciones (intenta saltar, cantar, ir al norte o al sur, e incluso SAVE y LOAD). Verás que el juego tiene respuestas para todo ¿de dónde las saca? ¡No hemos programado ninguna de esas respuestas!
He aquí uno de los principios básicos de Inform que lo diferencia claramente de PAWS. En PAWS, el programador tenía que programar las respuestas a cada posible verbo bajo cada posible circunstancia. Los casos que no eran contemplados por el programador, no existían en el juego. En Inform, en cambio, el programador sólo necesita especificar las respuestas a algunos verbos y en algunos casos. Todos los casos que el programador no contemple, serán manejados de forma automática por la librería. Es la librería la que tiene todas esas respuestas preparadas para las acciones más corrientes que el jugador intentará.
Pasemos a explicar línea a línea el programa que has copiado. Puedes saltarte esto e ir directamente a la programación del mapa si ya estás familiarizado con la sintaxis de Inform.
Constant Story "La Torre"; |
Con esto definimos una constante llamada Story. Esta constante
debe
definirse en todo juego Inform y contiene el título del juego.
El
valor de esta constante tiene que ser un texto entre comillas. En
nuestro caso el texto es "La Torre"
Observa que al final
del todo debe ponerse un
punto y coma. En Inform, todas las "declaraciones" van terminadas
por punto y coma.
Constant Headline "^(c) 2000 Zak y Carlos^"; |
Este es análogo al anterior, sólo que ahora la
constante que definimos
se llama Headline
y su valor es "^(c) 2000 Zak y
Carlos^"
. La
constante Headline
debe existir también en todo
juego Inform y es el
"subtítulo" del juego. El signo ^
representa un
salto de línea, es
decir, causa que antes de imprimir el texto el cursor pase a la
línea
siguiente (y otro salto tras escribir el texto, puesto que hay otro
^
al final).
Include "Parser"; |
Include
es lo que se llama una "directiva", esto es,
una orden que
le das a Inform para que haga algo. En este caso lo que le estás
ordenando es que coja el fichero llamado Parser.h
(la h
se la
pone automáticamente) y lo inserte en este punto. El resultado
es el
mismo que si hubieras copiado a mano tú mismo todo el contenido
de Parser.h
en este punto del fichero, sólo que
usando Include
el
código fuente del juego queda mucho más limpio y legible
(¡el fichero Parser.h
son miles de líneas!)
El fichero Parser.h
contiene el parser de Inform. Es
una parte de la librería que se ocupa de leer lo que el jugador
escribe, tratar de comprenderlo y generar acciones dentro del
juego. Enseguida veremos qué es eso de las acciones.
! Aqui iría la definición de mensajes de librería. |
Esta línea es lo que se llama un "comentario". Si Inform encuentra un signo de exclamación (!) que no esté formando parte de un texto entrecomillado, automáticamente ignorará todo lo que sigue en esa misma línea. Esto lo usaremos para poner anotaciones en el código. Estas anotaciones nunca formarán parte del juego final, una vez compilado, puesto que Inform las ignora.
En este caso la anotación es un recordatorio de dónde tendríamos que poner nuestras definiciones de mensajes de librería, si quisieramos ponerlas. En este juego no las pondremos de momento. Las definiciones de mensajes de librería son un poco como la tabla de mensajes de sistema de PAWS. Es donde se definen textos como "No puedes ir por ahi", "Cogido", "Cantas fatal", etc... Es decir, las respuestas por defecto de la librería ante cada posible acción. Si no definimos nosotros unas, la librería proporcionará otras ya preparadas. Puedes cambiar algunas de ellas si no te gustan sin necesidad de redefinirlas todas (y sin tener que modificar la librería). Luego veremos cómo.
Include "Verblib"; |
De nuevo mediante Include
, cargamos en nuestro juego
el fichero Verblib.h
, que contiene el código mediante el cual
la librería sabe
qué es lo que debe hacer ante cada posible acción.
(Enseguida veremos
qué son las acciones, son un concepto clave de Inform)
! Aqui irian las definiciones de las localidades ! y los objetos del juego |
Ahora se trata de unos comentarios recordándonos dónde irán los objetos y las localidades. Por el momento no hay ni objetos ni localidades.
[ Initialise ; ]; |
Esto es una rutina "libre". En Inform hay dos tipos de rutinas, las rutinas "libres" y las rutinas "incrustadas en objetos". Las libres son las que aparecen, como esta, en medio del código, las incrustadas en objetos aparecen siempre dentro de un objeto, luego daremos más detalles.
Una rutina no es más que un conjunto de instrucciones a las que hemos decidido agrupar y dar un nombre. En cierta manera se parece al concepto de "proceso" del PAWS, solo que en PAWS los procesos se identificaban mediante números (proceso 6, proceso 7,...) y en inform se identifican mediante nombres (rutina Initialise, rutina LugarNuevo, ...)
Todas las rutinas libres tienen la misma estructura:
[ Nombre_de_la_rutina v1 v2 v3; instruccion1; instruccion2; ... ]; |
Es decir:
[
indica que comienza la definición
de una rutina "libre".
_
(no se pueden poner acentos ni eñes)
v1
,
v2
y v3
. Más adelante veremos
más cosas sobre variables.
;
)
;
) Puedes poner varias
instrucciones en la misma línea (separadas por punto y coma), o
en líneas diferentes, el verdadero delimitador de instrucciones
es el punto y coma, y no el salto de línea, que para Inform es
lo mismo que un espacio.
]
;
)
Miremos otra vez el código que has escrito
[ Initialise ; ]; |
En nuestro caso, la rutina se llama Initialise
, su
lista de
variables locales está vacía (pues no hay nada entre el
nombre de la
rutina y el primer punto y coma), y también está
vacío su "cuerpo",
es decir, la lista de instrucciones que la componen (puesto que no hay
nada entre el primer punto y coma y el signo ]
que da por
terminada
la rutina).
En esencia: la rutina Initialise
que hemos escrito es
una rutina
totalmente vacía que no hace nada de nada. ¿Por
qué la ponemos
entonces? La razón es que esta rutina tiene que existir en todo
programa Inform, o de lo contrario Inform se negará a crear
tu
juego. Prueba a quitarla y lo verás.
![]() |
Para probar a quitar trozos
de código mientras estás de
pruebas, basta poner un signo de admiración delante de cada
línea que
quieras quitar. Esto convierte el código en "comentarios", por
lo
que se hace invisible a ojos de Inform. Si más tarde quieres
restituir
el código, basta borrar el signo de admiración. |
Normalmente esta rutina se ocuparía de especificar cuál es la localidad en que comienza el juego, y de imprimir algún mensaje de bienvenida, pero en este primer esbozo la hemos dejado vacía. Aún así funciona, no es ilegal escribir una rutina que no haga nada, aunque resulta poco útil.
Vamos a escribir el código de cada localidad. En Inform, cada localidad es un objeto. Esto puede sonarte un poco raro si pensabas que los objetos eran cosas como "una piedra", "una espada", etc. Pero es que el concepto de Objeto de Inform es mucho más amplio.
![]() |
En PAWS se llamaba "objetos" a
las cosas que el jugador podía coger y llevarse. En Inform el
concepto es muchísimo más amplio:
Para Inform, un objeto es en realidad un elemento del juego. Por tanto, los lugares son objetos, los PNJ son objetos, el propio jugador es un objeto, un "tema de conversación" puede ser un objeto. Prácticamente cualquier elemento de los que componen el juego son objetos (excepto las acciones o el vocabulario). Por eso se dice que Inform es orientado a objetos. |
Aunque todos los objetos tienen siempre una misma estructura, no vamos a entrar aún a describir la estructura general de los objetos, y nos centraremos de momento en la estructura de los objetos que representan lugares. Esta es su estructura:
Object nombre_interno "nombre corto" with description "Descripción larga de la localidad", n_to ... , s_to ... , e_to ... , w_to ... , u_to ... , d_to ... , in_to ... , out_to ... , has light; |
Es decir:
Object
, que le dice a Inform que aqui va
una definición de un objeto. La definición
terminará en un punto y coma (que ocurre al final del todo, tras
la palabra light
)
loc1
,
loc2
, loc3
, etc... Pero te aconsejo que
vayas olvidando la "forma PAWS de pensar" y uses nombres lógicos
para referirte a tus localidades, nombres como PuertaPrincipal
,
Dormitorios
, EscaleraCaracol
, etc. Estos
nombres nunca los verá el jugador. No pueden llevar acentos ni
eñes ni espacios. Sólo letras, números y el signo _
.
with
que indica a Inform que a
continuación viene una lista de "propiedades" de esa localidad.
Cada propiedad se separa de la siguiente mediante una coma.
description
.
Las propiedades son parejas, el primer elemento de la pareja es el
nombre de la propiedad (description
) y el segundo elemento
es el valor de esa propiedad (o sea, la descripción en concreto
de ese lugar). Entre ambos elementos de la pareja hay un espacio. La descripción es normalmente un texto, por lo que
debemos encerrarlo entre comillas dobles. El texto puede ser muy largo
por lo que ocuparía varias líneas de tu programa, no
obstante los lugares por donde cortes las líneas no influyen en
lo que el jugador verá. Su intérprete cortará las
líneas siempre por el lugar adecuado según el ancho de su
pantalla. Si quieres forzar un salto de línea, debes usar el
signo ^
(como en la constante Headline
).
Recuerda que una vez terminado el texto y cerradas las comillas, debes poner una coma para separar esta propiedad de las siguientes.
n_to
y su valor
indica a dónde se llega desde este lugar si se sale hacia el
norte. Los puntos suspensivos que hay después están
representando el nombre interno de otra localidad. Y detrás una
coma.
s_to
, e_to
,
etc indican a dónde llevan las restantes salidas de la
localidad. No es necesario listar todos los puntos cardinales, sino
sólo los que realmente llevan a algún sitio. Los que no
se listan, se entiende que son direcciones sin salida. (También
existen las direcciones nw_to
, sw_to
, ne_to
y
se_to
no usadas en el ejemplo)
has
(que en inglés significa "tiene").
light
, que como
puedes suponer indica que el lugar está iluminado. ¡Si
olvidaras poner ese atributo el jugador no podría ver la
descrcipción de la localidad a menos que llevara consigo
algún objeto con light
!
![]() |
Para los autores que usan informATE!,
puede parecerles dificultoso tener que lidiar ahora con los nombres de
propiedades, atributos, etc en ingles. Para aliviar un poco el asunto,
INFSP provee la extensión Alias.h , la cual da soporte para que se
puedan seguir usando los atributos y propiedades en español (como en
informATE!).
|
Una vez comprendida la estructura de las localidades, codificar el
mapa es pan comido. Copia el siguiente código en la zona donde
estaba
el comentario "Aquí irían las definiciones de las
localidades y los
objetos del juego"
. Observa que, de momento, ponemos conexión
"normal" en lugar de la puerta secreta.
Object PuertaPrincipal "Puerta Principal" with description "Estás junto a la puerta principal. A su lado puedes ver una mesa de guardia y en la pared norte hay una chimenea.", e_to Dormitorio, has light; Object Dormitorio "Dormitorio" with description "Varios maltrechos catres se amontonan en esta habitación.", w_to PuertaPrincipal, e_to EscaleraCaracol1, has light; Object EscaleraCaracol1 "Escalera de caracol" with description "El viento ulula a través de la empinada escalera de caracol, una vieja armadura parece vigilar la escalera.", u_to EscaleraCaracol2, w_to Dormitorio, has light; Object Mazmorra "Mazmorra" with description "Una silenciosa estancia débilmente alumbrada por los rayos de luna que se filtran a través de un pequeño ventanuco. El suelo está lleno de paja, colgando de unos grilletes en la pared observas un esqueleto humano.", e_to EscaleraCaracol2, has light; Object EscaleraCaracol2 "Escalera de caracol" with description "Los desgastados peldaños de piedra resbalan en ocasiones. A mitad de la escalera una antorcha en la pared impide que la oscuridad sea completa.", d_to EscaleraCaracol1, w_to Mazmorra, u_to AltoTorre, has light; Object AltoTorre "Alto de la torre" with description "Una gran cama preside la estancia, los gruesos barrotes no permiten la salida por la ventana, aunque de todos modos estaría demasiado alta.", d_to EscaleraCaracol2, has light; |
Unas notas sobre el código anterior:
EscaleraCaracol1
y a la otra EscaleraCaracol2
. Ahora será necesario también modificar la rutina Initialise
para
indicar en cuál de esas localidades comienza el juego.
En Inform, existe una variable global llamada location
que
contiene siempre la localidad en la que se halla el jugador. El
concepto de variable global es muy similar al concepto de "Bandera"
de PAWS, si bien en PAWS las banderas se identificaban mediante un
número (así la bandera que indicaba dónde
está el jugador, era la
bandera número 254), mientras que en Inform se identifican
mediante un
nombre (location
es el nombre de esta "bandera").
Otras
importantes diferencias son que en PAWS el número de banderas
estaba
limitado a 255, y no era necesario "declararlas" de antemano,
mientras que en Inform no hay límite al número de
variables globales,
pero es necesario declararlas de antemano (es decir, "anunciar" a
Inform de que vamos a crear una nueva variable global,
indicándole el
nombre que vamos a darle). La variable location
es
declarada en Parser.h
, el fichero que hemos incluido al principio.
Otra
diferencia importante es que en PAWS una bandera sólo
podía servir
para almacenar un número entre 0 y 255, mientras que en Inform
puede
usarse para almacenar un número entre -32768 y +32767, o
también una
palabra, una frase, un objeto, un lugar.. ¡cualquier cosa!
Para hacer que el lugar de comienzo sea la puerta principal, basta
cargar en la variable location
el objeto PuertaPrincipal
.
La
carga de una variable es algo análogo al condacto LET
del PAWS, pero
en Inform se usa la siguiente sintaxis:
variable = valor; |
Así, por ejemplo:
v2 = 32; |
Guardaría el número 32 dentro de la variable v2
,
de forma análoga a
lo que hacía el condacto LET
, mientras que:
v1=v2; |
Copiaría el valor de la variable v2
en la
variable v1
, de forma
análoga a lo que hacía el condacto COPYFF
De modo que ahora debes modificar la rutina Initialise
para que
ponga:
[ Initialise ; location = PuertaPrincipal; ]; |
Observa que ahora Initialise
ya no está
vacía. Tiene una sola
instrucción que sirve para asignar un valor a la variable location
. Recuerda que la instrucción debe
terminar con punto y
coma.
Otra interesante variable de Inform es una llamada lookmode
,
que controla si la descripción de la localidad debe repetirse o
no
cada vez que el jugador vuelve a entrar en una localidad en la que ya
había estado. El valor por defecto de esta variable implica que
la
descripción sólo se le muestre una vez, y si desea volver
a verla debe
escribir el verbo MIRAR. Si prefieres que la descripción se
muestre
siempre, debes hacer que esta variable tenga el valor 2 cuando el
juego comience, es decir, modifica Initialise
para que
sea:
[ Initialise ; location = PuertaPrincipal; lookmode=2; ]; |
Es importante que te acostumbres desde el primer momento a
"comentar" tu código, para que otros puedan comprenderlo y para
que
tú mismo lo entiendas cuando lo mires unas semanas más
tarde. Añadir
comentarios al juego no lo hace crecer de tamaño ¡recuerda
que Inform
ignora tus comentarios! Así que una rutina Initialise
más
"profesional" sería así:
[ Initialise ; ! Lugar de comienzo: la puerta principal location=PuertaPrincipal; ! Activamos esta variable para que la descripción de los lugares ! se repita siempre, incluso si el jugador ya ha estado allí lookmode=2; ]; |
Es habitual también incluir en la rutina Initialise
algún mensaje
de bienvenida al juego, o una introducción para situar al
jugador. El
comando para mostrar texto en Inform es print
, seguido
del texto en
cuestión encerrado entre comillas dobles. Por ejemplo:
print "¡¡Bienvenido a mi primer juego!!^^"; |
Como ya sabes, el signo ^
representa un salto de
línea. Poniendo dos
seguidos dejamos una línea en blanco debajo del texto
anterior. Observa que en Inform no hay tablas de mensajes de
usuario. No necesitas guardar tus textos en una tabla para
después
acceder a ellos mediante un número, sino que el texto lo pones
directamente a continuación del print. No olvides encerrarlo
entre
comillas.
Los juegos conversacionales escriben mucho texto. En juegos
complicados esto significa que habrá que usar muchas veces la
orden
print
, por ello Inform permite una abreviatura
especialmente útil,
pero un poco peligrosa para los principiantes. Consiste en no poner
print
, sino simplemente el texto entre comillas. Cuando
Inform
encuentra un texto entrecomillado en un lugar donde esperaba una
instrucción (o sea, dentro de una rutina), lo que hará
será imprimir
ese texto como si hubieras puesto print
delante,
añadir un salto de
línea al final (como si hubieras puesto un ^
justo
antes de cerrar
las comillas), y terminar la ejecución de la rutina
(algo
equivalente al DONE del PAWS).
![]() |
Esto es muy importante, merece
la pena repetirlo: una cadena entrecomillada en lugar de una
instrucción equivale a un print de la cadena,
seguido de un salto de línea y seguido del retorno inmediato de
la rutina en que aparece.
|
Por tanto, si queremos escribir un mensaje de bienvenida desde
nuestra
rutina Initialise
, tenemos varias posibilidades. En
primer lugar,
usando print
(forma recomendada a los principiantes):
[ Initialise; ! Lugar de comienzo: la puerta principal location=PuertaPrincipal; ! Activamos esta variable para que la descripción de los lugares ! se repita siempre, incluso si el jugador ya ha estado allí lookmode=2; ! Mensaje de bienvenida print "¡¡Bienvenido a mi primer juego!!^^"; ]; |
La orden print
puede aparecer en cualquier lugar
dentro de Initialise
, a fin de cuentas da lo mismo imprimir la
bienvenida
antes o después de haber inicializado las variables. La segunda
forma,
para programadores más expertos, es usar la abreviatura en la
que no
se pone print
. Quedaría así:
[ Initialise; ! Lugar de comienzo: la puerta principal location=PuertaPrincipal; ! Activamos esta variable para que la descripción de los lugares ! se repita siempre, incluso si el jugador ya ha estado allí lookmode=2; ! Mensaje de bienvenida "¡¡Bienvenido a mi primer juego!!^"; ]; |
En este caso, observa con atención los detalles siguientes:
^
en su interior, en
vez de dos, ya que cuando se omite print
, siempre se
añade un salto de línea automáticamente al final
del texto.
location
y lookmode
no llegarían a ser ejecutadas nunca (Inform te avisa de esto al
compilar).
Puedes ver el código fuente con todo esto ya tecleado aqui. Crea un nuevo fichero 'torre.inf' con el contenido del código, guárdalo (que no sea con Word, si no con Notepad o Vi, editor de texto plano), y lanza "inform torre.inf" desde CMD para compilarlo. Para ejecutarlo, lanza "frotz torre.z5" o bien arrastra el fichero Z5 encima del icono de WinFrotz.
Prueba a cambiar la descripción de una localidad, no tengas
miedo de
experimentar, es la única forma de aprender. ¿Cómo
modificarías el
programa para que bajando desde la PuertaPrincipal
se
llegue a un
Sotano
? ¡Hazlo! ¿Cómo
eliminarías la conexión que hay entre la
EscaleraCaracol1
y la Mazmorra
?
¡Hazlo!
![]() |
![]() |
![]() |
Por dónde empezar. |