SlideShare una empresa de Scribd logo
1 de 171
Descargar para leer sin conexión
Aetheria Game Engine


             Documentación de AGE


Cómo crear aventuras con Aetheria
         Game Engine


   Editor:                               Coordinador:
   Notxor                              Al-Khwarizmi
                      Varios Autores




             versión de 15 de octubre de 2012
Presentación de la
documentación

    Estimado lector:
    Esta documentación pretende servir de guía y referencia para crear aventuras
y otros juegos basados en texto para Aetheria Game Engine.
    Los juegos para AGE se crean mediante su herramienta de desarrollo, lla-
mada PUCK (Playable Universe Construction Kit). Esta herramienta permite
crear los elementos del mundo (habitaciones, cosas, criaturas...) y sus interac-
ciones básicas mediante un entorno gráfico, sin necesidad de programar. Para
conseguir comportamientos más complejos, dinámicos y personalizados, este en-
torno gráfico se complementa con un lenguaje de programación (similar a Java)
llamado BeanShell.
    Pero no te asustes: para aprender a crear juegos para AGE con este docu-
mento no es necesario tener ningún conocimiento previo de programación. Todos
los conceptos necesarios se explican desde cero, y crear juegos basados en texto
con PUCK es más sencillo que crear otro tipo de programas. Por lo tanto, aun-
que no sepas nada de programación, con esta guía estarás rápidamente creando
tus propios mundos interactivos; y si ya sabes algo, podrás saltarte varias de las
secciones introductorias.
    Esta versión en PDF de la documentación se ha generado a partir de la wiki
(que está en http://www.caad.es/aetheria/doc/doku.php), gracias al traba-
jo de Notxor, que ha maquetado el PDF. La documentación está en constante
proceso de ampliación y mejora, y las actualizaciones irán apareciendo primero
en la wiki para pasar después a sucesivas versiones de este fichero.
    No dudes dirigirme cualquier sugerencia o comentario, tanto como para me-
jorar el contenido de la documentación como para mejorar el propio sistema, al
email solrac888@yahoo.com.
    Atentamente,

                                                                  Al-Khwarizmi
                                                                Creador de AGE
Índice general

1. Uso  básico de puck                                                                           8
   1.1. Crear mundos con PUCK . . . . . . . . . . . . . . . .           .   .   .   .   .   .    8
   1.2. Creación de Mundos para AGE con PUCK: Resumen                   .   .   .   .   .   .    8
   1.3. Primeros Pasos: Creando Habitaciones y Caminos . . .            .   .   .   .   .   .   10
        1.3.1. Habitaciones y Caminos . . . . . . . . . . . . .         .   .   .   .   .   .   10
        1.3.2. Creando un Personaje Jugador . . . . . . . . .           .   .   .   .   .   .   14
   1.4. Seres inertes . . . . . . . . . . . . . . . . . . . . . . . .   .   .   .   .   .   .   16
        1.4.1. Descripciones de componentes . . . . . . . . . .         .   .   .   .   .   .   16
        1.4.2. Cosas . . . . . . . . . . . . . . . . . . . . . . .      .   .   .   .   .   .   17

2. Uso del lenguaje BeanShell                                                   24
   2.1. Primeros pasos con BeanShell . . . . . . . . . . . . . . . . . . . . 24
        2.1.1. Los formularios de código . . . . . . . . . . . . . . . . . . 25
        2.1.2. Los métodos . . . . . . . . . . . . . . . . . . . . . . . . . 25
        2.1.3. Variables y entrada/salida sencilla . . . . . . . . . . . . . 28
        2.1.4. La estructura condicional (if) . . . . . . . . . . . . . . . . 33
        2.1.5. Los bucles . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
        2.1.6. Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . 40
   2.2. Manipulación básica de entidades . . . . . . . . . . . . . . . . . . 41
        2.2.1. Método de análisis de la entrada referida a una entidad . 41
        2.2.2. Métodos para quitar, poner y mover entidades . . . . . . 43
        2.2.3. Las variables self y world . . . . . . . . . . . . . . . . . . . 45
        2.2.4. Métodos para comprobar dónde están las entidades . . . . 46
        2.2.5. Método de análisis de la entrada referida a dos entidades        48
        2.2.6. Variantes del método referido a dos entidades . . . . . . . 52
   2.3. propiedades y relaciones . . . . . . . . . . . . . . . . . . . . . . . 55
        2.3.1. Propiedades . . . . . . . . . . . . . . . . . . . . . . . . . . 55
        2.3.2. Temporización y método update . . . . . . . . . . . . . . 56
        2.3.3. Inicialización de propiedades . . . . . . . . . . . . . . . . 60
        2.3.4. Relaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
   2.4. Manejo de arrays y listas . . . . . . . . . . . . . . . . . . . . . . 64
        2.4.1. Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
        2.4.2. Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
   2.5. Errores comunes con BeanShell . . . . . . . . . . . . . . . . . . . 72
        2.5.1. Mensajes de error . . . . . . . . . . . . . . . . . . . . . . 72
        2.5.2. Tipos de error comunes . . . . . . . . . . . . . . . . . . . 76
        2.5.3. Funcionalidad de depuración . . . . . . . . . . . . . . . . 77
4                                                                                       Índice general


3. Aspectos avanzados del modelo de mundo                                                                        80
   3.1. Descripciones y nombres dinámicos . . . . . . . . . . . .                           .   .   .   .   .    80
        3.1.1. Descripciones dinámicas . . . . . . . . . . . . . .                          .   .   .   .   .    81
        3.1.2. Nombres dinámicos . . . . . . . . . . . . . . . . .                          .   .   .   .   .    82
   3.2. Cosas abribles y cerrables . . . . . . . . . . . . . . . . .                        .   .   .   .   .    83
        3.2.1. Definiendo cosas abribles y cerrables . . . . . . .                           .   .   .   .   .    83
        3.2.2. Llaves . . . . . . . . . . . . . . . . . . . . . . . .                       .   .   .   .   .    85
        3.2.3. Puertas . . . . . . . . . . . . . . . . . . . . . . .                        .   .   .   .   .    86
        3.2.4. Contenedores abribles y cerrables . . . . . . . . .                          .   .   .   .   .    87
   3.3. Contenedores . . . . . . . . . . . . . . . . . . . . . . . .                        .   .   .   .   .    87
        3.3.1. Definición y uso de contenedores . . . . . . . . .                            .   .   .   .   .    87
        3.3.2. Acciones sobre objetos contenidos . . . . . . . .                            .   .   .   .   .    89
   3.4. Miembros y prendas . . . . . . . . . . . . . . . . . . . .                          .   .   .   .   .    92
        3.4.1. Miembros . . . . . . . . . . . . . . . . . . . . . .                         .   .   .   .   .    92
        3.4.2. Prendas . . . . . . . . . . . . . . . . . . . . . . .                        .   .   .   .   .    93
   3.5. Estados de las criaturas . . . . . . . . . . . . . . . . . .                        .   .   .   .   .    95
        3.5.1. Las propiedades «state» y «target» . . . . . . . .                           .   .   .   .   .    96
        3.5.2. Cambios de estado . . . . . . . . . . . . . . . . .                          .   .   .   .   .    98
        3.5.3. Programación con estados . . . . . . . . . . . . .                           .   .   .   .   .    99
   3.6. Combate y armas . . . . . . . . . . . . . . . . . . . . . .                         .   .   .   .   .    99
        3.6.1. Elementos de rol básicos . . . . . . . . . . . . . .                         .   .   .   .   .   100
        3.6.2. Mecánica de combate . . . . . . . . . . . . . . .                            .   .   .   .   .   103
        3.6.3. Armas . . . . . . . . . . . . . . . . . . . . . . . .                        .   .   .   .   .   105
        3.6.4. Matemática de las armas . . . . . . . . . . . . .                            .   .   .   .   .   109
        3.6.5. Esquivadas . . . . . . . . . . . . . . . . . . . . .                         .   .   .   .   .   112
        3.6.6. Armaduras . . . . . . . . . . . . . . . . . . . . .                          .   .   .   .   .   113
        3.6.7. Entrando en combate . . . . . . . . . . . . . . .                            .   .   .   .   .   113
   3.7. Entidades abstractas . . . . . . . . . . . . . . . . . . . .                        .   .   .   .   .   114
   3.8. Hechizos . . . . . . . . . . . . . . . . . . . . . . . . . . .                      .   .   .   .   .   116
        3.8.1. Creación de hechizos en PUCK . . . . . . . . . .                             .   .   .   .   .   116
        3.8.2. Uso de hechizos por los jugadores . . . . . . . . .                          .   .   .   .   .   118
        3.8.3. Funcionamiento de los hechizos . . . . . . . . . .                           .   .   .   .   .   120
        3.8.4. Gestión de los puntos mágicos . . . . . . . . . . .                          .   .   .   .   .   126
        3.8.5. Uso de hechizos por los personajes no jugadores .                            .   .   .   .   .   127
   3.9. Mensajes por defecto . . . . . . . . . . . . . . . . . . . .                        .   .   .   .   .   128
        3.9.1. Cambiar los mensajes por defecto . . . . . . . . .                           .   .   .   .   .   128
        3.9.2. Generar dinámicamente los mensajes por defecto                               .   .   .   .   .   130

4. Métodos redefinibles                                                                                          131
   4.1. Eventos . . . . . . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   131
   4.2. Otros métodos redefinibles . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   131
        4.2.1. Métodos de Mobile (para PSIs)        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   131
        4.2.2. Ejemplo de uso . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   132

5. El análisis de la entrada                                                                                    133
   5.1. Métodos de análisis de la entrada (parseCommand)                        .   .   .   .   .   .   .   .   134
        5.1.1. Los métodos de análisis de la entrada . . .                      .   .   .   .   .   .   .   .   134
        5.1.2. Ejemplo de uso . . . . . . . . . . . . . . . .                   .   .   .   .   .   .   .   .   134
        5.1.3. Tipos de métodos de análisis de la entrada                       .   .   .   .   .   .   .   .   135
        5.1.4. El proceso de análisis de AGE . . . . . . .                      .   .   .   .   .   .   .   .   137
Índice general                                                                                             5


   5.2. Preprocesado de la entrada . . . . . . . . . . . . . .               .   .   .   .   .   .   .   139
   5.3. Gestión de verbos . . . . . . . . . . . . . . . . . . . .            .   .   .   .   .   .   .   140
        5.3.1. Visualización de la lista de verbos por defecto               .   .   .   .   .   .   .   141
        5.3.2. Añadir y quitar verbos . . . . . . . . . . . . .              .   .   .   .   .   .   .   142
        5.3.3. Verbos adivinables y no adivinables . . . . .                 .   .   .   .   .   .   .   142

6. Presentación del mundo                                                                                145
   6.1. Estilos de texto . . . . . . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   146
   6.2. Prompt . . . . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   146
        6.2.1. Métodos de manipulación del prompt            .   .   .   .   .   .   .   .   .   .   .   146
        6.2.2. Ejemplos de código . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   146
   6.3. Tipografías en AGE . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   147
        6.3.1. Control básico de la tipografía . . . .       .   .   .   .   .   .   .   .   .   .   .   147
        6.3.2. Control avanzado de la tipografía . . .       .   .   .   .   .   .   .   .   .   .   .   148
   6.4. Métodos gráficos . . . . . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   149
        6.4.1. Imágenes . . . . . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   149
        6.4.2. Frames . . . . . . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   152
   6.5. sonido . . . . . . . . . . . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   153
        6.5.1. Audio . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   153
        6.5.2. Música MIDI . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   156
   6.6. Otros aspectos de la presentación . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   158

7. Referencia de métodos invocables                                                                      159
   7.1. Manipulación del modelo de mundo . . . . . . . . . . . . . . .                           .   .   159
   7.2. Obtención de nombres de cosas y criaturas . . . . . . . . . . .                          .   .   159
        7.2.1. Obtención de nombres para mostrar . . . . . . . . . .                             .   .   159
   7.3. Notificación de acciones y sucesos . . . . . . . . . . . . . . . .                        .   .   162
        7.3.1. Notificar sobre algo que ha ocurrido en una habitación                             .   .   162
        7.3.2. Notificar sobre algo que ha ocurrido con una cosa . . .                            .   .   163
        7.3.3. Notificar sobre algo que ha ocurrido con una criatura .                            .   .   164
   7.4. Ejecución automática de órdenes . . . . . . . . . . . . . . . .                          .   .   164
        7.4.1. Añadir una orden a la cola de órdenes . . . . . . . . .                           .   .   165
        7.4.2. Ejecutar una orden lo antes posible . . . . . . . . . . .                         .   .   166
   7.5. Presentación general . . . . . . . . . . . . . . . . . . . . . . .                       .   .   168
   7.6. Métodos útiles de la API de Java . . . . . . . . . . . . . . . .                         .   .   168

8. Distribución como juego online                                                                        169
Lista de tablas
Índice de figuras

 1.1. Ventana de trabajo de puck. . . . . . . . . . . . . . . . . . . . . .               9
 1.2. Iconos de puck. . . . . . . . . . . . . . . . . . . . . . . . . . . . .            10

 3.1.   Relación tiempo ataque y Habilidad . . . . . . . . . . .    .   .   .   .   .   110
 3.2.   Relación tiempo ataque y Habilidad (real) . . . . . . . .   .   .   .   .   .   111
 3.3.   Probabilidad de éxito en el combate . . . . . . . . . . .   .   .   .   .   .   112
 3.4.   Diagrama del proceso de funcionamiento de un hechizo.       .   .   .   .   .   121
Capítulo 1

Uso básico de puck

1.1.      Crear mundos con PUCK
    El PUCK (Playable Universe Construction Kit) es una herramienta gráfica
de desarrollo que permite la creación de mundos interactivos para ser jugados
con el Aetheria Game Engine. Estos mundos pueden utilizarse para jugar
aventuras de texto, MUDs o juegos de rol mono y multijugador.
    En las siguientes secciones explicaremos detalladamente cómo se puede uti-
lizar PUCK para crear un juego completo. Empezaremos con un resumen que
nos dará una idea general de lo que tendremos que hacer, para luego entrar más
específicamente en cada una de las etapas de creación de un mundo.
    En la figura 1.1 puedes ver un ejemplo de aventura en PUCK.


1.2.      Creación de Mundos para AGE con PUCK:
          Resumen
    Un juego en Aetheria Game Engine viene dado por un mundo, y un mundo
es una colección de diferentes objetos, que pueden ser de diversos tipos:

       Habitaciones (también llamadas localidades), que son lugares del mundo
       conectados entre sí por caminos. Una habitación puede representar literal-
       mente una dependencia de una casa; pero también podría ser, dependiendo
       de la ambientación, un cruce de caminos, una calle, etc.

       Personajes, que son seres vivos que pueblan el mundo, incluyendo al
       jugador, y que se pueden mover entre habitaciones a través de los caminos.
       Por ejemplo, tenderos, camareros, enemigos, animales, el propio jugador,
       etc.

       Cosas, que son seres inertes que se encuentran en las habitaciones o que
       llevan los personajes. Por ejemplo, puertas, llaves, cofres, sillas, mesas,
       espadas, dinero, etc.

   Para crear un juego completo, necesitaremos hacer las siguientes cosas (no
necesariamente en orden):
Creación de Mundos para AGE con PUCK: Resumen                                  9




                   Figura 1.1: Ventana de trabajo de puck.

     Crear los objetos del juego,
     Crear las relaciones entre ellos (por ejemplo, un camino es una relación
     entre dos habitaciones. O, si un personaje lleva un objeto, entonces el
     personaje y el objeto están relacionados mediante una relación «leva»),
     Dar a los objetos nombres y descripciones para que se muestren en el
     juego,
     Dotar a los objetos de comportamiento, es decir, que puedan reaccionar
     ante lo que hace el jugador y los demás objetos.
    El PUCK (Playable Universe Construction Kit) da soporte a todas estas
actividades de la siguiente manera:
     La creación de objetos se hace en el editor gráfico que ocupa la parte iz-
     quierda de la ventana de PUCK. Las herramientas crear habitación, crear
     personaje y crear cosa permiten crear los objetos y colocarlos en el mundo:
     simplemente haz click sobre la herramienta correspondiente en la barra de
     herramientas, y a continuación lleva el objeto creado hasta el lugar del
     mundo en el que lo quieres poner. Nota: la representación gráfica del mun-
     do es simplemente una herramienta de conveniencia. El lugar del panel
     donde coloques un objeto no tendrá ninguna relevancia en el juego, así
     que simplemente colócalos como más cómodos te sean para verlos y ma-
     nipularlos.
     La creación de relaciones entre objetos se hace también en el editor gráfico,
     mediante las herramientas crear relación estructural y crear relación au-
     xiliar. Para crear una relación, basta con hacer click sobre la herramienta
10                                                           Uso básico de puck




                           Figura 1.2: Iconos de puck.


       correspondiente, y a continuación sobre los dos objetos que se desea rela-
       cionar. La representación gráfica de cada relación es una flecha.

       La descripción de los objetos se hace en los paneles de objeto que apare-
       cen en la parte derecha de la ventana de PUCK. Para acceder al panel de
       un objeto dado, basta con hacer click sobre él en la representación gráfi-
       ca cuando ninguna herramienta está seleccionada. Se nos mostrará toda
       la información de ese objeto (nombres, descripciones, etc.) y podremos
       modificarla.

       Por último, la descripción del comportamiento se hace también en los
       paneles de objeto. Ésta es la parte de la creación de un mundo en la
       que entra en juego la programación, para lo cual se utiliza el lenguaje de
       scripting BeanShell. El código para cada objeto se modifica en la ficha
       «Código y Propiedades» de su panel de objeto correspondiente.



1.3.      Primeros Pasos: Creando Habitaciones y Ca-
          minos
1.3.1.     Habitaciones y Caminos
   Veamos ahora cómo podemos usar PUCK para definir un mundo. Lo primero
que haremos será crear un par de habitaciones unidas entre sí mediante un
camino, de manera que el jugador pueda hacer algo como esto:
   >mirar
Primeros Pasos: Creando Habitaciones y Caminos                                     11


    Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor.
Un precario puente de madera lo atraviesa, hacia el oeste.
    >ir hacia el oeste
     Atraviesas el puente hacia el oeste cuidadosamente. Las tablas de madera que
lo forman crujen inquietantemente; pero llegas sano y salvo a la otra orilla.
    Te encuentras al oeste del gran río Pecos. Hay unos cuantos árboles altos a tu
alrededor. Un tosco puente de madera lo atraviesa, hacia el este.
    >ir por el puente
    Atraviesas el puente hacia el este con sumo cuidado. Las tablas que lo componen
emiten crujidos inquietantes; pero llegas sin incidencias a la otra orilla.
    Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrede-
dor. Un precario puente de madera lo atraviesa, hacia el oeste.

    Para ello, lo primero que debemos hacer es ir al menú «Archivo – Nuevo»,
que nos creará un nuevo mundo en blanco para trabajar.
    Al hacer esto veremos a la izquierda el editor gráfico en blanco, que es donde
colocaremos nuestros objetos; y a la derecha el panel de objeto asociado al
mundo. En este panel aparece un formulario con una serie de propiedades del
mundo. Es recomendable cubrir al menos el nombre corto y el nombre largo, que
AGE utilizará para identificar el mundo. El nombre corto debería estar formado
por una única palabra, aconsejablemente de no más de doce caracteres; mientras
que el nombre largo puede ser un título de la longitud que se desee, y es lo que
se mostrará al jugador como nombre de la aventura. El resto de campos (autor,
versión, fecha...) son datos meramente informativos que se mostrarán al jugador
cuando vaya a cargar el juego.
    Si queremos dejar estas propiedades para más tarde, o modificarlas en algún
momento, es conveniente saber que podemos volver cuando queramos a este
panel de mundo, simplemente seleccionando una zona vacía del editor gráfico.
    Pero pasemos a la acción: vamos a crear las dos habitaciones del ejemplo,
situadas una al oeste de otra y separadas por un camino (puente). Para ello
hacemos lo siguiente:

      Hacemos click en icono de la herramienta «añadir habitación» de la barra



      de herramientas.

      Movemos el cursor por el editor gráfico. Veremos que aparece un cuadrado
      (la habitación que estamos creando) que se mueve junto a nuestro cursor.
      Hacemos click, y la habitación quedará fija en el editor. A la derecha
      podremos ver su panel de objeto.

      Hagamos que esta habitación represente la orilla oeste del gran río Pecos.
      Para ello, cubrimos los campos del panel de objeto:

         • Donde pone «Nombre único», pondremos un nombre corto como por
           ejemplo «Oeste Pecos». Este nombre no se mostrará al jugador, se
           utiliza para identificar internamente la habitación en el juego y dis-
           tinguirla de las demás. Nosotros también lo utilizaremos cuando nos
           queramos referir a esta habitación en el futuro.
12                                                            Uso básico de puck


       • Donde pone «Descripciones» irán las descripciones de la habitación,
         que son lo que se muestra al jugador cuando teclea «mirar» o cuando
         entra en la misma. Puede extrañarte que no haya una sola «Des-
         cripción», sino un campo para «Descripciones». Esto es porque las
         descripciones en AGE no son un texto estático, sino algo que puede
         variar según distintas condiciones (por ejemplo, la descripción de una
         localidad puede ser distinta según si es de día o de noche). El sistema
         que se utiliza para hacer posible esto es que la descripción que se
         muestra al jugador esté formada por distintos trozos que se pueden
         mostrar o no dependiendo de las condiciones que se den. En este ca-
         so, nos conformaremos con una descripción estática, con lo cual sólo
         necesitaremos uno de estos trozos, y sin ninguna condición asocia-
         da. Para ello, donde pone «Descripción» teclearemos la descripción
         completa de la habitación:
         Te encuentras al oeste del gran río Pecos. Hay unos cuantos árboles altos
         a tu alrededor. Un tosco puente de madera lo atraviesa, hacia el este.
         Y pulsamos el botón «Añadir». Vemos que la descripción introduci-
         da aparecerá en el cuadro «Descripciones», precedida de la palabra
         «Siempre». Esto último quiere decir que esta descripción se mostrará
         siempre que un jugador mire la habitación, es decir, no está sujeta a
         condición alguna.
     Por el momento no necesitamos añadir nada más a esta habitación. Es
     bueno saber que, si más tarde queremos modificar sus datos, basta con
     hacer click sobre su representación en el editor gráfico (cuando no estemos
     usando ninguna herramienta) para poder ver y modificar de nuevo su panel
     de objeto.
     Del mismo modo que creamos la habitación anterior, creamos una nueva
     para representar la orilla este del río. Para ello, tenemos que volver a hacer
     click en la herramienta «añadir habitación», ya que cada uso de la herra-
     mienta sirve para añadir una sola vez. Colocaremos la nueva habitación a
     la derecha de la anterior, dado que se encuentra al este. Si no hemos dejado
     espacio suficiente en el editor gráfico para colocarla, podemos utilizar las
     herramientas de desplazamiento y zoom:
       • Para usar la herramienta de desplazamiento, hacemos click sobre su




          icono en la barra de herramientas:             A continuación, hace-
          mos un click sobre el editor gráfico, y movemos el cursor: los objetos
          del editor se desplazarán con él. Con otro click dejamos de usar la
          herramienta.
       • La herramienta zoom se utiliza del mismo modo. Después de hacer




          click en su icono            y en el editor gráfico, podemos mover el
          ratón hacia arriba para alejar la vista o hacia abajo para acercarla.
Primeros Pasos: Creando Habitaciones y Caminos                                 13


     Rellenamos el nombre único y la descripción de la nueva habitación de
     la misma manera que lo habíamos hecho con la anterior, reflejando que
     estamos al este del Pecos.
     Ahora vamos a crear la conexión entre las dos habitaciones. Como po-
     demos ver en el texto de lo que queremos conseguir, las dos localidades
     deben estar unidas por un puente que cruza de este a oeste. El puente se
     debe poder cruzar en las dos direcciones; pero es importante saber que en
     AGE los caminos son de una sola dirección. Por lo tanto, para permitir
     el tránsito en las dos direcciones tenemos que crear dos caminos: uno de
     oeste a este y otro de este a oeste. Nótese que, aunque esto pueda parecer
     incómodo para casos simples, hace el sistema más poderoso, porque se
     puede dar tratamiento distinto a cada sentido del camino, incluyendo per-
     mitir el paso en un solo sentido, tener descripciones distintas para ambos,
     hacer que suceda algo al cruzar en un sentido dado, etc.
     Para crear los caminos, utilizaremos la herramienta «añadir relación es-
     tructural» de la barra de herramientas, que está identificada por este icono:




     Las relaciones en AGE son formas de expresar cualquier tipo de relación,
     permanente o temporal, entre dos objetos. Existen dos tipos de relaciones:
     relaciones estructurales y relaciones auxiliares. Las estructurales se llaman
     así porque son las que definen la estructura del mundo: nos dicen dónde
     están los objetos. También se caracterizan porque un objeto no tendría
     ningún sentido si no estuviese (o al menos pudiese estar) conectado al resto
     del mundo mediante relaciones estructurales. Las relaciones auxiliares se
     utilizan para definir otros aspectos de las interacciones entre objetos.
     Un camino se modela en AGE como una relación estructural entre una
     habitación y otra, de ahí que se cree con esta herramienta. Para crear un
     camino entre las dos habitaciones, seguimos los siguientes pasos:
       • Hacemos click sobre la herramienta «añadir relación estructural»




       • Hacemos click sobre la habitación que representa el Oeste del Pecos.
       • Hacemos click sobre la otra habitación. Veremos que aparece una
         flecha entre las dos habitaciones, que representa el camino que las
         une.
     Al igual que los objetos, podemos ver que las relaciones también tienen
     paneles de objeto. Nada más crear esta relación camino, podremos ver
     en la parte derecha de la ventana de PUCK su panel correspondiente.
     El panel tiene algunos campos ya cubiertos, como son las habitaciones
     origen y destino (que son las que marcamos en el mapa) y la dirección
14                                                              Uso básico de puck


     estándar, que es un punto cardinal asociado al camino. Como habíamos
     colocado una habitación a la derecha de la otra, el camino aparecerá auto-
     máticamente marcado con la dirección estándar «este». Esto implica que
     se podrá utilizar con comandos como «ir al este». Si a pesar de haber
     colocado las habitaciones de esa manera éste no era el comportamiento
     que queríamos, podemos cambiar la dirección estándar (o quitarla para
     no tener ninguna) en el panel de objeto correspondiente al camino. Del
     mismo modo podríamos cambiar en cualquier momento las habitaciones
     origen y destino, podemos ver que para esto se utiliza el «nombre único»
     que hace referencia a cada habitación.

     Debajo de estos campos podemos ver una lista, inicialmente vacía, de co-
     mandos personalizados. En esta lista podemos introducir todas aquellas
     palabras que el jugador pueda usar para referirse a este camino además
     del punto cardinal dado por la dirección estándar. Como queremos que el
     jugador pueda teclear cosas como «ir puente» o «ir por el puente», añadi-
     mos «puente»: para ello, introducimos la palabra donde pone «Comando»
     y pulsamos el botón «Añadir».

     A continuación podemos ver un área para descripciones, que ya debería
     resultarnos familiar. Las descripciones para los caminos funcionan exacta-
     mente igual que para las habitaciones; pero se muestran cuando el jugador
     cruza el camino correspondiente. Así, para obtener el comportamiento que
     buscamos para este camino, debemos teclear en el campo «Descripción»:
     Atraviesas el puente hacia el este con sumo cuidado. Las tablas que lo com-
     ponen emiten crujidos inquietantes; pero llegas sin incidencias a la otra orilla.

     Con esto tenemos todo lo que necesitábamos por el momento para este
     camino. Cuando volvamos a necesitar modificar este panel de objeto, basta
     con que hagamos click sobre la flecha que representa el camino en el mapa
     para acceder a él.

     Para crear el otro camino, como es imaginable, basta con repetir el mismo
     proceso; pero haciendo click primero sobre la habitación del este y luego
     sobre la del oeste. Nos aparecerá otra flecha en dirección opuesta, que
     no se solapa con la anterior para que podamos hacer click fácilmente en
     cualquiera de ellas accediendo a su correspondiente panel de objeto. La
     descripción y el comando personalizado se introducen del mismo modo.


1.3.2.    Creando un Personaje Jugador
    Con esto ya hemos creado un mínimo mundo con el que jugar; pero nos falta
un elemento necesario para que la aventura tenga sentido: un personaje que pue-
da recorrerlo. En AGE, los jugadores están en la piel de personajes que habitan
en el mundo e interactúan con él (aunque también pueden crearse personajes
que no sean jugadores). Por lo tanto, incluso en un juego para un solo jugador
deberemos poner al menos un personaje que represente a ese jugador para que
se pueda jugar. Para ello, utilizaremos la herramienta «añadir personaje» de la
barra de herramientas:
Primeros Pasos: Creando Habitaciones y Caminos                                15




   Y haremos lo siguiente:

     Para usar esta herramienta, procedemos de la misma manera que cuando
     añadimos habitaciones al mundo: hacemos click sobre su icono en la ba-
     rra de herramientas, deslizamos el cursor por el editor gráfico y hacemos
     click sobre el punto en que queremos dejar al personaje. Será conveniente
     que lo coloquemos cerca de la habitación donde queremos que el jugador
     aparezca al principio del juego; pero –ojo, importante– no dentro de ella.
     Esto es porque en el editor gráfico el hecho de que algo esté dentro de
     una habitación no se representa colocando su icono dentro de la misma;
     sino uniendo la habitación a ese algo mediante una relación estructural.
     Representar unas cosas dentro de otras podría parecer más natural a sim-
     ple vista; pero resultaría engorroso cuando una habitación contuviese gran
     número de personajes o cosas.
     Así pues, el siguiente paso será crear la relación estructural entre la ha-
     bitación (que puede ser la oeste o la este, dependiendo de dónde queréis
     que empiece el personaje: lo que creamos con PUCK es siempre el estado
     inicial del mundo, que luego podrá cambiar durante el juego cuando los
     personajes se muevan y manipulen los objetos) y el personaje. Para ello,
     utilizamos la herramienta «crear relación estructural» que ya conocemos:




                  y hacemos click primero sobre la habitación y luego sobre el
     personaje (el orden es importante). Esto nos creará una relación estructu-
     ral de tipo «contiene» que significa que la habitación contiene al personaje,
     y que, al contrario que la relación «camino» que veíamos antes, no tiene
     nada que configurar.
     Para que todo funcione, sólo falta una cosa: especificar que el personaje
     que hemos creado es un jugador. Para ello, hacemos click sobre él para
     obtener su panel de objeto, y marcamos la casilla que dice «jugador».
     Esto hace que, cuando alguien arranque la aventura, el AGE lo ponga en
     la piel de este personaje (en juegos multijugador las cosas son algo más
     complicadas; pero ya las veremos).
     Si hurgamos en el panel de objeto asociado al personaje podemos ver
     que tiene diversos datos configurables, como por ejemplo nombre único
     y descripciones. Estas últimas funcionan del mismo modo que las de las
     habitaciones y caminos, y en este caso se mostrarían si el jugador se mirase
     a sí mismo. Puedes cubrirlas si quieres; aunque no son necesarias para el
     comportamiento que queríamos.

    Ahora sí que tenemos un mundo de AGE completo y jugable (aunque, de
momento, no muy emocionante). Para jugarlo, no tenemos más que hacer click
en la herramienta Ejecutar mundo:
16                                                               Uso básico de puck




    La herramienta nos recuerda que para probar la aventura tiene que guardar
el fichero (lo hará automáticamente) y nos da a elegir entre dos interfaces de eje-
cución: el SDI (ventana simple) o el MDI (ventana con sub–ventanas). Podemos
escoger cualquiera de los dos; aunque para propósitos de prueba de aventuras
de un solo jugador el SDI suele resultar suficiente y más sencillo. Después, le
damos al botón Aceptar para ejecutar la aventura.
    Si lo hemos hecho todo bien, podremos jugar la partida que hemos visto al
principio de la sección.
    No se puede decir que haya sido difícil, ¿verdad? Pues ahora vamos a mejo-
rarlo.


1.4.      Seres inertes
1.4.1.     Descripciones de componentes
    En la sección 1.3, hemos visto algunos conceptos básicos de PUCK y hemos
definido un mundo rudimentario con un par de habitaciones y caminos. Por el
momento, lo único que este mundo permite hacer al jugador es desplazarse de
una habitación a otra a través de los caminos; pero la interacción con el mundo
no va mucho más allá. Por ejemplo:
    >mirar
    Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor.
Un precario puente de madera lo atraviesa, hacia el oeste.
    >mirar los árboles
    ¿Qué pretendes mirar?
    >mirar el puente
    ¿Qué pretendes mirar?
    Parece que una primera característica deseable para mejorar la interacción
del jugador con el mundo sería que se pudiesen mirar los objetos que apare-
cen mencionados en las descripciones. Así, nos gustaría que cuando el jugador
pusiese «mirar los árboles», apareciese una descripción de los mismos para dar
ambientación. La forma más sencilla de conseguir esto en AGE mediante las
llamadas descripciones de componentes o descripciones extra. Las descripciones
de componentes pueden añadirse a casi cualquier objeto del mundo (incluyendo
habitaciones, personajes, cosas, etc.) y siguen siempre el mismo sistema, que es
una extensión del que seguían las descripciones convencionales que hemos visto.
    Así, si en la sección anterior veíamos que las descripciones convencionales
eran realmente listas de descripciones, cada una de las cuales tenía asociada una
condición (que por el momento habíamos dejado en blanco para que se mostraran
siempre) y un texto; las descripciones extra también serán listas de descripciones;
pero cada una tendrá asociada una serie de nombres, una condición y un texto.
Si añadimos una descripción extra a una localidad y el jugador teclea «mirar
‘algo’» (o alguna frase sinónima) en ella, entonces se mostrará la descripción si
ese ‘algo’ coincide con uno de los nombres y además la condición asociada se
cumple.
Seres inertes                                                                 17


    Vamos a hacer que el jugador pueda mirar los árboles y el puente desde la
localidad oeste. Para ello, hacemos click sobre esta localidad en el editor grá-
fico, y nos aparece su panel de objetos. Debajo de la sección de descripciones
convencionales que ya tenemos cubierta, vemos la sección «Descripciones de
componente». En el campo «Nombres de ref. sep. por comas» tecleamos, sin las
comillas: «árbol,árboles»; y en el campo «Descripción» ponemos lo que quere-
mos que le aparezca al jugador cuando mire los árboles, como puede ser «Son
unos árboles muy verdes y muy bonitos.» Como en ocasiones anteriores, dejamos
el campo «Condición» vacío, ya que esta descripción no dependerá de ninguna
condición externa, y pulsamos el botón «Añadir». En la lista de descripciones
extra veremos algo como «árbol,árboles: Siempre: Son unos árboles muy verdes
y muy bonitos», donde se muestran los nombres y la descripción; y la palabra
«Siempre» indica que la descripción va a mostrarse siempre que el jugador mire,
sin depender de ningún otro factor.
    Lo mismo podemos hacer con el puente si añadimos una descripción extra con
nombre «puente» y descripción «Es un precario puente de madera.» o cualquier
texto similar. Si queremos que el puente se vea desde las dos localidades, como
sería lógico, tenemos que poner su descripción extra en ambas.

1.4.2.    Cosas
    Las descripciones de componentes proporcionan una primera manera de ha-
cer el mundo más interesante y llegar un poco más allá de las habitaciones y
caminos; pero tienen sus limitaciones. Las descripciones de componentes nos
permiten definir elementos del mundo que los jugadores pueden mirar; pero la
posible interacción con ellos se reduce sólo a eso: a mirar.
    A la hora de crear un juego decente, esto seguramente no sea suficiente. Nos
interesan objetos físicos con los que los jugadores puedan interactuar de más
maneras: cogerlos, llevarlos en su inventario, dejarlos en alguna otra parte, y
seguramente hacer más cosas dependiendo del tipo de objeto que sea. Este tipo
de objetos físicos son lo que en AGE denominamos «cosas».
    Para probar las cosas, vamos a crear una piedra que el jugador pueda al
menos coger, llevar y dejar. En capítulos posteriores del tutorial veremos cómo
hacer cosas más complejas (por ejemplo que puedan abrirse y cerrarse, llevar
otras cosas dentro, etc.); pero por el momento empezaremos por lo básico.

Creación de cosas
   Al contrario que las descripciones extra, las cosas son objetos de pleno dere-
cho en AGE, y tienen una representación gráfica en el editor del PUCK. Para
añadir una cosa, utilizamos la herramienta «añadir cosa»:




   A la hora de utilizar esta herramienta, procedemos de manera análoga a
cuando habíamos añadido un personaje al mundo: hacemos click sobre el icono
de «añadir cosa», movemos el cursor por el editor gráfico hasta dejarlo en la
ubicación deseada para el objeto (que no debe coincidir con la habitación en la
que queremos ponerlo; aunque sí es conveniente que esté cerca), y hacemos click
18                                                                   Uso básico de puck


sobre esa ubicación. Para colocar la cosa en una localidad, igual que habíamos
hecho con el personaje, creamos una relación estructural: hacemos click en la
herramienta «crear relación estructural»




    y a continuación en la habitación y en la cosa, por ese orden. Esto creará una
relación «contiene» entre habitación y cosa que indica que la cosa está situada
en dicha habitación.

Características básicas de cosas
    Una vez que tenemos nuestra cosa creada y vinculada a una habitación, ha-
cemos click en su icono del editor gráfico para ver su panel de objeto. Los paneles
de objeto de las cosas son algo más complicados que los de las habitaciones; pero
algunos de sus componentes nos resultarán familiares, y otros los aprenderemos
fácilmente.
    En primer lugar podemos ver el campo para el nombre único, que funciona
igual que el de las habitaciones, sirviendo para distinguir internamente el objeto.
En este punto es conveniente aclarar que los nombres únicos deben ser realmente
únicos, es decir, no debe haber en un mundo dos objetos con el mismo nombre
único, ni siquiera si son objetos de tipos completamente distintos. Esto quiere
decir que no debes ponerle a una cosa un nombre que hayas utilizado para, por
ejemplo, una habitación. A nuestro objeto podemos llamarle «Piedra».
    Bajo el nombre único, debajo de unos campos «Heredar de:» y «Ejemplo
de:» que no veremos por el momento, podemos ver un campo de «Género»,
que nos da a elegir entre masculino y femenino. El género de una cosa es el
género que tiene en castellano el nombre de esa cosa, y se utiliza para construir
los textos del juego. Si pusiésemos que la piedra es «Masculino», podríamos
obtener textos en el juego como «aquí hay un piedra» o «coges el piedra del
suelo», así que es importante cubrir bien este campo si queremos un mundo que
hable decentemente el idioma.
    Debajo del género, podemos ver unos campos para el «Peso» y el «Volumen»
de la cosa que, como es imaginable, representan el peso y el volumen que tiene el
objeto en el mundo virtual que estamos creando. Aunque se pueden utilizar para
más cosas, la consecuencia más inmediata de estos valores es que un personaje no
podrá llevar consigo objetos que superen el máximo peso y volumen que pueda
acarrear. Si en tu juego no quieres prestar atención a esos detalles, simplemente
puedes dejar el peso y el volumen de todos los objetos a cero. En este caso
podemos poner, por ejemplo, peso y volumen 5.
    Después de los campos correspondientes al peso y el volumen, hay en el
formulario dos opciones llamadas «Contenedor» y «Fijo en el sitio». La opción
«Contenedor» puede marcarse para representar cosas que puedan tener otras
cosas dentro, como una bolsa o un baúl.1 La opción «Fijo en el sitio» denota un
     1 El
        autor de AGE recomienda a título personal no usar los contenedores en juegos más
de lo estrictamente necesario, pues tienden a complicar innecesariamente la vida al jugador
al tener que preocuparse de sacar y meter objetos de dentro de otros, cosa que puede ser
interesante cuando es parte del argumento de la aventura (encontrar la llave de un antiguo
baúl, etc.) pero no aporta mucho si se usa como elemento de ambientación.
Seres inertes                                                                 19


objeto que no se puede coger, como una farola o una montaña; todas las cosas
que no tengan esta opción marcada serán por defecto susceptibles de ser cogidas
por los jugadores. En el caso de la piedra, lo lógico será no marcar ninguna de
las dos opciones, ya que una piedra no puede contener otras cosas en su interior,
y queremos que el jugador la pueda coger.
    A continuación están las descripciones y las descripciones de componentes,
que se rellenan de la misma manera que en las habitaciones. Las descripcio-
nes en este caso aparecerán cuando un jugador ponga «mirar ‘nuestra cosa’», y
funcionarán tanto si el jugador lleva consigo la cosa como si simplemente está
en la misma localidad. Las descripciones de componentes se pueden usar para
describir partes o características de los objetos: por ejemplo, si nuestro objeto
es una linterna, podemos usar una descripción extra para describir el botón de
encendido de la linterna. Si ponemos como nombre para la descripción de com-
ponente «botón», y nuestra linterna respondía al nombre «linterna», el jugador
podrá ver la descripción extra tecleando «mirar el botón de la linterna». Noso-
tros nos limitaremos a añadir una descripción convencional para la piedra, algo
como: «Es una piedra estándar, de las de toda la vida. Podrías abrir cabezas
con ella.»

Nombres para mostrar y nombres de referencia
    Todo lo mencionado está en la ficha «General» del panel de objeto, que
es la que hemos visto hasta ahora en todos los objetos que hemos creado. Sin
embargo, puede que ya te hayas fijado en que algunos de ellos tienen más fichas
aparte de ésta, y es el caso de nuestra recién creada piedra. Ahora vamos a ir
a la segunda ficha, llamada «Nombres». Cubrir esta ficha es esencial para crear
una cosa, porque nos permite definir el nombre o nombres de dicha cosa.
    Hasta ahora, en la ficha «General» del panel habíamos visto el «Nombre
único» de la cosa, que nos servía para identificarla. Pero, como ya mencionamos
al hablar de habitaciones, los nombres únicos de los objetos sólo se usan para
que los distinga el creador del juego y el propio juego; sin que se muestren en
ningún caso al jugador. Por lo tanto, tendremos que definir otros nombres (que
pueden coincidir o no con el nombre único) para mostrar al jugador y para que
el jugador pueda interactuar con la piedra.
    En la ficha «Nombres» podemos ver espacio para poner cuatro tipos de nom-
bres: «Nombres singulares para mostrar», «Nombres plurales para mostrar»,
«Nombres singulares de referencia» y «Nombres plurales de referencia».
    Los dos primeros tipos son los nombres que se mostrarán al jugador, y fun-
cionan exactamente igual que las descripciones. Si queremos que el objeto se
llame siempre de una manera determinada y ya está, basta con que tecleemos
su nombre en el campo «Nombre:» de «Nombres singulares para mostrar» y
pulsemos «Añadir». En nuestro caso, si añadimos de esta manera el nombre
«piedra», esto se traducirá en el juego a textos como «aquí puedes ver una
piedra», «coges la piedra» «dejas la piedra», «llevas una piedra»... Si quisiése-
mos que el nombre de un objeto cambiase según circunstancias del juego (por
ejemplo, la piedra podría convertirse en una «piedra mojada» si le echásemos
agua por encima), tendríamos que añadirle más nombres singulares y asociarles
diferentes condiciones. Nosotros nos conformaremos con un nombre estático, así
que añadimos «piedra» sin especificar condición alguna.
    Los «Nombres plurales para mostrar» se utilizan para mostrar al jugador
20                                                               Uso básico de puck


si hay varios objetos iguales en un mismo sitio. Por ejemplo, para que el juego
pudiese construir frases como «llevas dos piedras» o «aquí hay tres piedras»,
tendríamos que añadir «piedras» como nombre plural. Si no va a haber varios
objetos iguales en el juego que se puedan agrupar de esta manera, como es
nuestro caso, podemos dejar los nombres plurales en blanco. Más adelante ve-
remos cómo se pueden crear varios objetos idénticos que se puedan agrupar, y
utilizaremos estos nombres plurales.
    Los «Nombres singulares de referencia» son aquellos nombres por los cuales el
jugador se puede referir al objeto. Estos nombres no se muestran en la aventura;
pero serán los que el sistema utilice para saber que el jugador se ha referido en su
orden a un objeto dado. Como al jugador puede ocurrírsele referirse a una cosa
usando una palabra que no sea el nombre que se le muestra en pantalla, suele
ser recomendable incluir sinónimos en los nombres de referencia. Por ejemplo,
en este caso podemos añadir los siguientes nombres de referencia para la piedra:
«piedra», «roca» y «pedrusco». Después de teclear cada nombre en el campo
«Nombre», pulsamos el botón «Añadir» para colocarlos en la lista, o podemos
pulsar «Cambiar» para modificar alguno si nos hemos equivocado. De este modo,
el jugador podrá referirse a la piedra mediante comandos como «coger piedra»,
«dejar roca» o «mirar pedrusco», y todos serán entendidos como referidos a
nuestro objeto piedra.
    En los «Nombres plurales de referencia» pondremos los nombres por los
cuales el jugador se puede referir a un conjunto de objetos que incluya éste.
Normalmente, tendremos aquí las versiones de los nombres singulares de refe-
rencia: en este caso «piedras», «rocas» y «pedruscos». De esta forma, si hay
varias piedras (todas con esos nombres de referencia) y el jugador pone «coger
las piedras» o «coger todas las rocas», su orden se ejecutará sobre todas ellas.
Un truco que suele venir bien, y podemos hacer en este caso, es poner como
último nombre plural de referencia «todo». De esta manera, cuando el jugador
ponga «coger todo», su orden actuará sobre todos los objetos que tengan ese
nombre plural de referencia.

Interacciones básicas con las cosas
    Una vez rellenados de este modo los nombres para mostrar y de referencia de
nuestra piedra, podemos utilizar la herramienta «Ejecutar mundo» para probar
el objeto que hemos creado. Deberíamos ser capaces de hacer estas cosas:
    >mirar
    Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor.
Un precario puente de madera lo atraviesa, hacia el oeste.
    Aquí hay una piedra.
    >mirar los árboles
    Son unos árboles muy verdes y muy bonitos.
    >mirar la piedra
    Es una piedra estándar, de las de toda la vida. Podrías abrir cabezas con ella.
    >coger la roca
    Coges la piedra.
    Es una piedra estándar, de las de toda la vida. Podrías abrir cabezas con ella.
    >inventario
    Tienes una piedra.
    >dejar todo
Seres inertes                                                                     21


   Dejas la piedra.
   >inventario
   No tienes nada.
   >mirar
   Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor.
Un precario puente de madera lo atraviesa, hacia el oeste.
   Aquí hay una piedra.

Cosas con el mismo nombre de referencia
    Como hemos visto, los nombres de referencia nos determinan cómo el jugador
se puede referir a una cosa. Pero a veces podría darse el caso de que varias cosas
compartan un mismo nombre de referencia. Por ejemplo, supongamos que hemos
definido las siguientes dos cosas:

      Una piedra blanca, que tiene como nombre para mostrar «piedra blan-
      ca», y como nombres de referencia «piedra blanca», «pedrusco blanco»,
      «piedra», «pedrusco».

      Una piedra negra, que tiene como nombre para mostrar «piedra negra», y
      como nombres de referencia «piedra negra», «pedrusco negro», «piedra»,
      «pedrusco».

    En este ejemplo, hemos puesto «piedra» como nombre de referencia de ambas
piedras para que cuando el jugador encuentre una de ellas pueda simplemente
teclear comandos como «coger piedra» y funcionen, sin especificar el color:
    Aquí hay una piedra blanca.
    >coger la piedra
    Coges la piedra blanca.
    Sin embargo, ¿qué pasará si el jugador teclea «coger la piedra» en una habi-
tación donde está tanto la piedra blanca como la negra? ¿Cuál de ellas cogerá?
    La respuesta es que los nombres de referencia tienen una prioridad corres-
pondiente a la posición que ocupan en la lista de nombres de referencia de
PUCK (posición más alta quiere decir mayor prioridad). Cuando un jugador
teclea una orden, las palabras que siguen al verbo se comparan con los nombres
de referencia de los objetos que están al alcance del jugador, seleccionándose
aquellos nombres de referencia que aparezcan mencionados en las palabras te-
cleadas. En el caso de que haya un único nombre de referencia seleccionado de
este modo (o varios, pero todos pertenecientes a la misma cosa), la acción se
ejecuta sobre la cosa que tiene ese nombre. En el caso de que se seleccionen
nombres de referencia de diferentes cosas, la acción se ejecuta sobre aquélla a
la que perteneza el nombre de referencia de mayor prioridad (es decir, el que
aparece más arriba en la lista) de entre los seleccionados. En el caso de que haya
un empate a prioridades, se ejecuta sobre un objeto cualquiera.
    Por ejemplo, si en el caso de las piedras blanca y negra hemos introducido
los nombres de referencia en el orden especificado arriba, las prioridades para la
piedra blanca serían:

      Prioridad 1. piedra blanca

      Prioridad 2. pedrusco blanco
22                                                           Uso básico de puck


       Prioridad 3. piedra
       Prioridad 4. pedrusco

     Y para la piedra negra serían:

       Prioridad 1. piedra negra
       Prioridad 2. pedrusco negro
       Prioridad 3. piedra
       Prioridad 4. pedrusco

    Si el jugador teclea «coger la piedra blanca», en la orden tecleada aparecen
nombres de prioridad 1 y 3 de la piedra blanca (aparece «piedra blanca», de
prioridad 1, pero también aparece «piedra», de prioridad 3, como parte de la
cadena). Sin embargo, de la piedra negra, sólo aparece un nombre de prioridad
3 («piedra»). Como la prioridad 1 le gana a la prioridad 3, el jugador cogerá la
piedra blanca.
    Si el jugador teclea «coger el pedrusco negro», en la orden aparece un nombre
de prioridad 4 de la piedra blanca («pedrusco») y nombres de prioridad 2 y 4
de la piedra negra («pedrusco negro» y «pedrusco»). Como la prioridad 2 es
mayor que la prioridad 4, el jugador cogerá la piedra negra.
    ¿Qué pasa si el jugador teclea simplemente «coger una piedra»? En este caso
para ambos objetos se seleccionaría un nombre de prioridad 3 («piedra»). Como
hay empate a prioridades, el jugador cogería una piedra cualquiera: se supone
que ambas se ajustan por igual a la orden dada por el jugador, así que si sólo ha
especificado «coger una piedra», debería servirle cualquiera de los dos. Si por
algún motivo quisiéramos asegurarnos de que con esta orden el jugador siempre
cogiese una piedra dada (por ejemplo, la blanca); tendríamos que hacer que el
nombre de referencia «piedra» tuviese más prioridad en esa piedra que en la
otra.
    En general, para que este sistema de prioridades para los nombres de referen-
cia nos conduzca a una interpretación natural de las órdenes de los jugadores,
lo único que tendremos que hacer es poner los nombres más específicos por en-
cima de los más genéricos (tal y como hemos hecho en el ejemplo de la piedra).
Entrando más en detalle, lo que necesitamos es que si un nombre de referencia
es específico de un objeto, tenga más prioridad que los nombres más genéricos
de otros objetos que puedan entrar en conflicto con ese nombre específico. Por
ejemplo, si el nombre específico «piedra blanca» tuviera prioridad 3 en la piedra
blanca y el nombre genérico «piedra» tuviera prioridad 1 en la piedra negra,
tendríamos problemas, porque al «coger la piedra blanca» ganaría la piedra
negra al tener el nombre genérico «piedra» con más prioridad que el nombre
específico «piedra blanca» de la piedra blanca. Sin embargo, casos como éste
prácticamente nunca se podrán dar si seguimos la norma general de que, dentro
de cada cosa, los nombres específicos aparecen antes que los genéricos. Siguien-
do esta simple regla, normalmente no hará falta acordarse de cómo funciona el
sistema de prioridades salvo para casos avanzados en los que se quiera tener un
control muy detallado de las maneras de referirse a cada objeto.
    Nótese que, si en lugar de nombres singulares de referencia hablamos de
nombres plurales de referencia, con estos últimos la acción no se ejecutará sobre
Seres inertes                                                                23


un solo objeto, sino con todos los que tengan un nombre plural de referencia
seleccionado. Es decir, si las dos piedras del ejemplo tienen como nombre plural
de referencia la palabra «piedras», entonces la orden «coger las piedras» hará
que el jugador coja ambas, independientemente de las prioridades.
Capítulo 2

Uso del lenguaje BeanShell

    Los formularios de PUCK, como los vistos en el capítulo anterior, propor-
cionan una manera sencilla de construir un mundo con diferentes localizaciones
y objetos que los jugadores puedan manipular; sin necesidad de escribir código
en ningún lenguaje de programación. Sin embargo, si queremos conseguir mun-
dos complejos donde las entidades exhiban comportamientos dinámicos y donde
podamos definir acciones personalizadas que vayan más allá de los comporta-
mientos por defecto, sí que necesitaremos programar.
    Para estas definiciones de comportamientos complejos que requieren progra-
mación, AGE utiliza el lenguaje BeanShell. BeanShell es un lenguaje de scripting
muy parecido a Java. De hecho, la sintaxis de Java se puede utilizar tal cual en
BeanShell; pero éste además permite usar variables con tipado dinámico y tiene
otras características donde «relaja» los requisitos de Java.
    Para añadir código BeanShell a un mundo con PUCK, se puede ir a la pesta-
ña «Código y Propiedades» de cualquier entidad (las entidades son los objetos
del mundo representados por iconos que añadimos en el mapa de PUCK, como
habitaciones, cosas y criaturas) o bien del propio mundo, y nos aparecerá un
área de texto (con un botón «Ampliar» que la convierte en una ventana inde-
pendiente) para introducir el código. AGE es un sistema orientado a objetos, de
modo que el código que modifique el comportamiento de una entidad determina-
da deberá introducirse en el campo de código de esa entidad. El campo de código
del mundo permite hacer modificaciones más globales en el comportamiento de
la aventura.
    A lo largo de las secciones de este capítulo veremos una introducción a cómo
programar en BeanShell para crear aventuras en AGE. Esta información se
ampliará en subsiguientes capítulos, donde la entremezclaremos con más cosas
que se pueden hacer en los formularios de PUCK; ya que ambas cosas no son
independientes sino que hay aspectos de PUCK que hacen uso o interactúan
con el código BeanShell, haciendo necesario tratarlas de forma entrelazada.


2.1.     Primeros pasos con BeanShell
    BeanShell es un lenguaje orientado a objetos, basado en Java, que se utiliza
para definir comportamientos avanzados en entidades y mundos de AGE. En
ésta y las siguientes secciones, describiremos cómo se puede usar BeanShell
Primeros pasos con BeanShell                                                                         25


para este propósito. Esto quiere decir que no veremos exhaustivamente todas
las características de BeanShell, sino que sólo describiremos lo necesario para
utilizarlo en AGE de forma lo más sencilla posible. Los programadores que
quieran un conocimiento más completo y riguroso de BeanShell, incluyendo
todas sus características y no limitado a AGE, pueden consultar su página web
http://www.beanshell.org.

2.1.1.        Los formularios de código
    En los formularios de «Código y propiedades» de PUCK se puede escribir
código BeanShell. Este código puede estar asociado a una entidad concreta
del mundo (una habitación, cosa, etc.), en el caso de que lo escribamos en el
formulario de una entidad; o al mundo en su conjunto, si lo escribimos en el panel
del mundo. La idea es que el comportamiento de cada entidad se especifique
dentro de esa entidad, de modo que las entidades sean unidades autocontenidas
que se puedan llevar fácilmente de un mundo a otro. Por ejemplo, si definimos
una máquina de coser, querremos que el código que usamos para que cosa esté
definido en la entidad «máquina de coser»: de este modo no sólo queda más claro
dónde buscar el código de cada cosa, sino que además nos podríamos llevar esa
entidad a otra aventura y seguiría cosiendo. El panel de código del mundo, por lo
tanto, se utilizará para comportamientos que no estén asociados a una entidad
particular, sino al juego en general.

2.1.2.        Los métodos
    El código que escribamos en un formulario siempre tendrá que constar de
uno o más métodos. Un método es una porción de código que recibe unos datos
de entrada y los procesa de una u otra manera, y, para los que vengan de otros
lenguajes, es algo análogo al concepto de función o subrutina.
    El código de un método consta de una cabecera, que indica qué datos espera
el método como entrada y cuáles produce como salida, y un cuerpo escrito entre
llaves que contiene las instrucciones ejecutadas por el método. Las cabeceras de
los métodos no hace falta escribirlas, las podemos generar directamente con los
menús del PUCK. Sólo hará falta escribir, pues, el cuerpo de los métodos (parte
delimitada por llaves).
    Por ejemplo, en el siguiente método:
v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s )
{
    i f ( e q u a l s ( verb , " s a l u d a r " ) )
       a C r e a t u r e . w r i t e ( " H o l a .  n" ) ;
   end ( ) ;
}

    La cabecera es
v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s )

    donde:

   1. Mobile aCreature, String verb, String args es la lista de argumentos o pa-
      rámetros de entrada del método. Cada parámetro corresponde a un dato
      que el método espera recibir cuando se ejecute. Cuando usemos BeanShell
26                                                    Uso del lenguaje BeanShell


       para mundos en AGE, normalmente será el AGE quien invoque la mayoría
       de los métodos y nos proporcione los datos de los parámetros.
     2. Cada una de las tres partes separadas por comas en la lista de parámetros
        (por ejemplo, String verb) es la definición de un parámetro de entrada.
        Un método puede tener cualquier cantidad de parámetros de entrada,
        incluyendo no tener ninguno (en cuyo caso no habría nada dentro de los
        paréntesis). La declaración de un parámetro consta de un tipo de dato
        y un identificador o nombre. En el ejemplo, String sería el tipo de dato
        (indicando que ese parámetro es una cadena de texto) y verb sería el
        nombre. El tipo de dato tiene que ser uno de los que soporta AGE o
        Java (hay formas de crearlos nuevos, pero no las usaremos); mientras que
        el nombre es totalmente arbitrario mientras dentro del mismo método
        nos refiramos al parámetro siempre por el mismo nombre: por ejemplo,
        podríamos haberle llamado a ese parámetro verbo en lugar de verb, y todo
        funcionaría igual mientras cambiáramos ese nombre también en el cuerpo
        del método (if ( equals(verbo,"saludar") )); pero no podríamos hacer un
        cambio semejante con el tipo de dato.
     3. Algunos de los tipos de datos más usados son:
             int: número entero.
             boolean: representa algo que puede ser verdadero o falso, tiene dos
             valores válidos: true o false.
             double: permite representar números con cifras decimales.
             char: representa una letra o símbolo.
             String: cadena de texto.
             World: mundo de AGE.
             Entity: cualquier entidad del mundo.
             Item: cosa del mundo.
             Mobile: criatura del mundo.
             Room: habitación del mundo.
     4. Al escribir los tipos de datos, es importante respetar las convenciones de
        mayúsculas y minúsculas que se ven en la lista (BeanShell es sensible a
        mayúsculas y minúsculas). El motivo de que unos tipos de dato se escriban
        con minúscula y otros con mayúscula es que los que son con mayúscula
        corresponden a objetos (y se llaman clases, es decir, Room es un tipo de
        dato que es una clase y la habitación de Pedro sería un objeto de tipo
        Room) mientras que los que son con minúscula son tipos de datos que se
        llaman básicos y corresponden a valores (como el entero −4, el booleano
        false o el double 3,25) y no a objetos. En AGE usaremos muy pocos tipos
        básicos (de hecho, sólo los de la lista y uno más que mencionaremos ahora
        mismo); sin embargo podremos usar bastantes clases (no sólo las de la
        lista), que iremos viendo.
     5. parseCommand es el nombre del método, que junto con los tipos de los
        parámetros (no sus nombres) es lo que lo identifica y distingue de otros.
        En general, el nombre puede ser cualquier palabra que cumpla ciertas
Primeros pasos con BeanShell                                                   27


         reglas (por ejemplo si tiene sólo letras mayúsculas y minúsculas siempre
         servirá).
    6. Lo que viene antes del nombre, en este caso void, es el tipo de retorno del
       método. Y es que, además de procesar unos parámetros de entrada, un
       método puede devolver un resultado como salida. El tipo básico void es
       un tipo básico especial que no tiene ningún valor, y se utiliza en el caso
       en que un método no devuelve nada.
    7. En general, podemos definir métodos con cualquier combinación de nom-
       bre, parámetros y tipo de retorno. Pero como normalmente vamos a querer
       que AGE ejecute nuestros métodos, para que así queden integrados en el
       conjunto de la aventura, necesitaremos ponerles unos nombres (y tipos de
       parámetros y de retorno, aunque no necesariamente nombres de paráme-
       tros, que como dijimos son arbitrarios) determinados que son los que el
       AGE espera encontrar. Sin embargo, no es necesario saber de memoria los
       nombres y parámetros de los métodos que invoca AGE, ya que el PUCK
       nos generará automáticamente una plantilla de los mismos desde los me-
       nús contextuales de los formularios de código. Por ejemplo, si en el PUCK
       abrimos el área en que se introduce el código del mundo y vamos a su
       menú contextual con el botón derecho, seleccionando la opción «Insertar
       código – Método de análisis de la entrada (estándar)» se nos generará au-
       tomáticamente una plantilla que contendrá la cabecera del método y unos
       comentarios sobre para qué sirve el método y la función de cada pará-
       metro. Eso sí, el cuerpo del método que aparece automáticamente estará
       vacío y por lo tanto no hará nada, tendremos que rellenarlo nosotros para
       que haga algo.
    8. Si generamos esta plantilla, o cualquier otra con el PUCK, veremos tex-
       to que viene después de dobles barras. El texto que viene en una línea
       después de una doble barra es un comentario de código y no se ejecuta,
       es simplemente para que nosotros escribamos explicaciones de qué hace
       ese código o cosas que queramos recordar. Lo mismo sucede con el texto
       comprendido entre /* y */, que puede ocupar una o varias líneas. Los
       comentarios de código pueden ir en cualquier parte del mismo: sea en la
       cabecera de un método, en su cuerpo, o incluso fuera de cualquier método,
       ya que AGE los ignora por completo y no los ejecuta.

// e s t o e s un c o m e n t a r i o
/∗ y e s t o
t a m b i é n ∗/

     El cuerpo del método del ejemplo anterior es el código entre llaves:
{
    i f ( e q u a l s ( verb , " s a l u d a r " ) )
       a C r e a t u r e . w r i t e ( " H o l a .  n" ) ;
    end ( ) ;
}

   Y lo que hace es que, si la cadena (verbo) que nos han pasado como segundo
parámetro corresponde a la palabra «saludar» (sin comillas), entonces escribi-
mos una línea que dice «Hola.» en la salida asociada a la criatura que viene
dada como primer parámetro.
28                                                                     Uso del lenguaje BeanShell


2.1.3.        Variables y entrada/salida sencilla
    Ahora que ya sabemos que tenemos que definir métodos y que estructura
básica tienen, y tenemos una idea de cómo obtener sus cabeceras con el PUCK,
vamos a ver qué tipo de cosas podemos poner en los cuerpos de los métodos para
ejecutar código útil. Para ello, por el momento siempre partiremos del método
void parseCommand(Mobile aCreature, String verb, String args) cuya cabecera se
genera automáticamente en la opción «Insertar código – Método de análisis de
la entrada (estándar)» del menú contextual del campo de código de mundo.
Ese método lo invoca AGE cuando un jugador introduce una entrada, y los
parámetros que recibe son, por orden: el objeto que representa al jugador que
ha escrito esa entrada (de momento el único jugador, ya que nos centraremos
en aventuras para un solo jugador), el verbo que ha puesto (o primera palabra
de la cadena que ha tecleado en la entrada), y el resto de la cadena de entrada.
Por ejemplo, si el jugador teclea «comer el plátano de Canarias», entonces el
parámetro aCreature corresponderá a ese jugador, el parámetro verb a la cadena
«comer», y args a la cadena «el plátano de Canarias».


Mostrándole texto al jugador

    Una de las primeras cosas que podemos hacer es probar a mostrar un texto
al jugador cada vez que se ejecute el método (es decir, en el caso de este método
particular, cada vez que escribe algo). Esto podríamos hacerlo así:

v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s )
{
    a C r e a t u r e . w r i t e ( " H o l a .  n" ) ;
}


    Si ponemos este código en el mundo, cada vez que el jugador escriba algo,
AGE le dirá «Hola». La sintaxis aCreature.write("Hola.n") significa que
queremos al método write del objeto aCreature, y pasarle como parámetro la
cadena "Hola.n". Para ello, tiene que haber definido en la clase a la que
pertenece aCreature (o sea, la clase Mobile) un método llamado write que coja
una cadena como único parámetro, y efectivamente, este método existe, y lo que
hace es escribir algo por la ventana o consola de esa criatura. El punto y coma
sirve para terminar la instrucción. Se pueden ejecutar varias instrucciones en
secuencia, una después de otra, escribiéndolas una después de otra. No se debe
olvidar poner un punto y coma después de cada una:

v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s )
{
    a C r e a t u r e . w r i t e ( " E s t a l í n e a s e e s c r i b e p r i m e r o .  n" ) ;
    a C r e a t u r e . w r i t e ( "Y é s t a s e e s c r i b e " ) ;
    a C r e a t u r e . w r i t e ( " d e s p u é s .  n" ) ;
}


    La secuencia de caracteres n dentro de una cadena significa un salto de
línea. Por lo tanto, este código escribirá dos líneas, una que dirá «Esta línea se
escribe primero.» y otra que dirá «Y ésta se escribe después.».
Primeros pasos con BeanShell                                                                                 29


La función end()
   Si probamos a ejecutar nuestra aventura de ejemplo con el código que hemos
añadido, veremos que la salida es algo similar a esto:

> inventario
Esta línea se escribe primero.
Y ésta se escribe después.
No tienes nada.
> asdasf
Esta línea se escribe primero.
Y ésta se escribe después.
No entiendo...

    Es decir, nuestra aventura está diciéndole escribiéndole al jugador el texto
cada vez que escribe algo, pero después está siguiendo el procesado normal que
hace AGE (por ejemplo, mostrar el inventario si lo que escribió fue «inventario»).
    Si en lugar de esto se quiere que el método que hemos definido sustituya al
procesado por defecto de AGE, es decir, que cuando un jugador escriba algo se
le escriba el texto dado y nada más, podemos utilizar la función end():
v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s )
{
            a C r e a t u r e . w r i t e ( " E s t a l í n e a s e e s c r i b e p r i m e r o .  n" ) ;
            a C r e a t u r e . w r i t e ( "Y é s t a s e e s c r i b e " ) ;
            a C r e a t u r e . w r i t e ( " d e s p u é s .  n" ) ;
            end ( ) ;
}

    De esta forma nuestra salida será

> inventario
Esta línea se escribe primero.
Y ésta se escribe después.
> asdasf
Esta línea se escribe primero.
Y ésta se escribe después.

    Podemos utilizar la función end() para interrumpir el procesado normal del
AGE en cualquier momento de la mayoría de los métodos. La plantilla que el
PUCK genera de cada método da información explícita sobre si se puede usar
o no la función end().
    A end() le hemos llamado función, y no método, porque no está asocia-
da a un objeto. Un método se invoca sobre un objeto, con la sintaxis obje-
to.método(parámetros),1 mientras que una función se invoca sin más, con la
sintaxis función(parámetros).

Variables y asignaciones
    En BeanShell, como en otros muchos lenguajes de programación, una varia-
ble es un nombre simbólico que se asocia a un determinado valor u objeto en
   1 O a veces sobre una clase, con la sintaxis Clase.método(parámetros). Los métodos que se

invocan sobre una clase se llaman métodos estáticos
30                                                                 Uso del lenguaje BeanShell


memoria, que pueden cambiar a lo largo de la ejecución del código. Los pará-
metros de los métodos, que vimos con anterioridad, son un tipo particular de
variables que almacenan los datos y objetos que se pasan como entradas a un
método; pero como programadores también podemos crear otras variables para
almacenar todo tipo de información temporal que se utilice en el interior de un
método.
    Una variable tiene tres atributos esenciales: su nombre, su tipo de dato y su
valor. El nombre es simplemente una palabra que el programador escoge para
referirse a la variable, mientras que el tipo de dato describe qué valores puede
contener la variable. Los tipos de datos son los mismos que hemos visto en la
sección sobre los parámetros de los métodos, que pueden ser tipos básicos o
clases.
    Un ejemplo de uso de variables podría ser el siguiente: si estamos escribiendo
un código para describir todos los objetos que un jugador lleva en su inventario,
probablemente usaremos una variable para llevar cuenta de cuántos objetos
llevamos descritos (que será de tipo int, pues el número de objetos descritos
en cada momento es un número entero) y otra variable donde almacenaremos
temporalmente cada objeto al consultarlo en el inventario para describirlo (que
será de la clase Item, que representa las cosas en AGE).
    Para crear una nueva variable, se utiliza una sintaxis como ésta:
int index ;

    donde int es el tipo de datos de la variable que queremos declarar, e index es
su nombre.
    Para asignarle un nuevo valor a una variable ya declarada, lo hacemos de la
siguiente manera:
index = 0;

    Con este código estamos haciendo que la variable entera index tome como
valor el número entero 0. Es importante tener en cuenta que cada variable sólo
puede tomar valores legales según su tipo de datos. Por ejemplo, a una variable
entera le podemos dar el valor 0; pero no le podemos dar el valor «Hola» o 3,5,
porque éstos no son números enteros.
    Aquí vemos cómo podemos asignar valores a variables de distintos tipos:
int index ;
d o u b l e number ;
boolean c o n d i t i o n ;
char l e t t e r ;
S t r i n g name ;
Room aRoom ;
Item anItem ;
Mobile aCreature ;

i n d e x = −4;
number = 7 . 2 3 ;
c o n d i t i o n = t r u e ; // o f a l s e
l e t t e r = ’ a ’ ; // l o s v a l o r e s de t i p o c a r á c t e r s e e s c r i b e n
                                       // e n t r e c o m i l l a s s i m p l e s
name = " P a b l o P i c a s s o " ; // l o s v a l o r e s de t i p o c a d e n a ( S t r i n g )
                                       // s e e s c r i b e n e n t r e c o m i l l a s d o b l e s
aRoom = room ( " S a l a d e l t r o n o " ) ; // room ( ) e s una f u n c i ó n a l a que
                                       // l e pasamos una c a d e n a y n o s d e v u e l v e l a
Primeros pasos con BeanShell                                                                              31


                                            // h a b i t a c i ó n que t i e n e e s a c a d e n a como
                                                  nombre ú n i c o
a n I t e m = i t e m ( " B o l í g r a f o " ) ; // i t e m ( ) e s a n á l o g o a room ( ) ,
                                            // p e r o con una c o s a
a C r e a t u r e = m o b i l e ( " Juan " ) ; // m o b i l e ( ) e s a n á l o g o a room ( ) ,
                                            // p e r o con una c r i a t u r a

   Este proceso se puede abreviar asignando un valor inicial a las variables a la
vez que las creamos, de la siguiente manera:
i n t i n d e x = −4;
d o u b l e number = 7 . 2 3 ;
boolean c o n d i t i o n = true ;
char l e t t e r = ’ a ’ ;
S t r i n g name = " P a b l o P i c a s s o " ;
Room aRoom = room ( " S a l a d e l t r o n o " ) ;
Item anItem = item ( " B o l í g r a f o " ) ;
M o b i l e a C r e a t u r e = m o b i l e ( " Juan " ) ;

    A las variables también se les puede asignar el valor de otra variable, o el
valor que devuelve una expresión (que puede contener operaciones o llamadas a
métodos o funciones):
int index = 7;
i n t i n d e x 2 = i n d e x ; // c o p i a m o s e l v a l o r de i n d e x a i n d e x 2 ,
                          // a h o r a i n d e x 2 v a l e 7
i n t i n d e x 3 = i n d e x 1 + i n d e x 2 ; // l a e x p r e s i ó n i n d e x 1 + i n d e x 2
                          // d e v u e l v e l a suma de i n d e x 1 e i n d e x 2 , a h o r a i n d e x 3
                                   v a l e 14
i n d e x 3 = i n d e x 3 + 1 ; // i n c r e m e n t a m o s i n d e x 3 en 1

I t e m arma = i t e m ( " Espada " ) ; // ob t e n e mo s e l o b j e t o de nombre
                              // ú n i c o " Espada " y l o almacenamos en l a v a r i a b l e
                                     arma
i n t pesoArma = arma . g e t W e i g h t ( ) ; // g e t W e i g h t ( ) e s un método de l a
                              // c l a s e I t e m que n o s d e v u e l v e e l p e s o de una c o s a .
                                     Aquí ponemos
                              // e l p e s o de n u e s t r a e s p a d a en l a v a r i a b l e pesoArma
                                     . Nótese
                              // que podemos h a c e r e s t o p o r q u e e l t i p o de r e t o r n o
                                     del
                              // método g e t W e i g h t ( ) e s i n t , y e l t i p o de l a
                                     variable
                              // pesoArma t a m b i é n e s i n t . En g e n e r a l no podemos
                                     asignar
                              // a una v a r i a b l e un v a l o r que no s e a de s u t i p o
i n t d o b l e P e s o A r m a = arma . g e t W e i g h t ( ) ∗ 2 ; // e l ∗ e s e l o p e r a d o r
                              // de m u l t i p l i c a c i ó n . Como vemos , s e pueden c o m b i n a r
                                       llamadas
                              // a métodos con o p e r a c i o n e s p a r a f o r m a r una
                                     e x p r e s i ó n que
                              // d e v u e l v e un v a l o r , v a l o r que s e pu e de d e s p u é s
                                     m e t e r en una v a r i a b l e

arma = 7 ; // e s t o      f a l l a r í a porque intentamos a s i g n a r a l a
                          // v a r i a b l e arma , de t i p o Item , e l v a l o r 7 , de t i p o
                                  int .
                          //No c o i n c i d e n l o s t i p o s , a s í que l a a s i g n a c i ó n no
                                 s e p ue de
                          // l l e v a r a cabo
32                                                                      Uso del lenguaje BeanShell


Operaciones con los tipos básicos
    En la sección anterior hemos visto algunos ejemplos de cómo se hacen opera-
ciones, como por ejemplo una suma. Veamos aquí una lista algo más exhaustiva
de operaciones útiles.
    Con int:
int   a = 7;
int   b = 4;
int   c;
c =   a + b;     // suma a y b ( c v a l d r í a 1 1 )
c =   a − b;     // r e s t a a menos b ( c v a l d r í a 3 )
c =   a ∗ b;     // m u l t i p l i c a a p o r b ( c v a l d r í a 2 8 )
c =   a / b;     // d i v i s i ó n e n t e r a de a e n t r e b ( c v a l d r í a 1 )
c =   a %b;      // r e s t o de l a d i v i s i ó n e n t e r a de a e n t r e b ( c v a l d r í a 3 )
      .

a++; // i n c r e m e n t a l a v a r i a b l e a ( e s e q u i v a l e n t e a p o n e r a = a + 1 )
a−−; // d e c r e m e n t a l a v a r i a b l e a ( e s como p o n e r a = a − 1 )

a ∗= 3 ; // a b r e v i a t u r a de a = a ∗ 3 . E s t o s e p ue d e h a c e r
    análogamente
         // con t o d o s l o s o p e r a d o r e s de l o s t i p o s b á s i c o s que
               aparecen
         // en e s t a s e c c i ó n .

     Con double:
d o u b l e a = 7 . 0 ; // n ó t e s e e l . 0 p a r a i n d i c a r que e l v a l o r s e
             // c o n s i d e r a un d o u b l e y no un i n t , aunque m a t e m á t i c a m e n t e
             // s e a e l mismo v a l o r
double b = 4 . 0 ;
double c ;
c = a + b ; // suma a y b ( c v a l d r í a 1 1 . 0 )
c = a − b ; // r e s t a a menos b ( c v a l d r í a 3 . 0 )
c = a ∗ b ; // m u l t i p l i c a a p o r b ( c v a l d r í a 2 8 . 0 )
c = a / b ; // d i v i s i ó n con d e c i m a l e s de a e n t r e b ( c v a l d r í a 1 . 7 5 )

     Con cadenas:
S t r i n g a = " Juan " ;
S t r i n g b = " Pepe " ;
S t r i n g c = a + b ; // l a " suma " de c a d e n a s e s s u
             // c o n c a t e n a c i ó n : l a c a d e n a " JuanPepe "

int a = 7;
double b = 3 . 0 ;
S t r i n g m e n s a j e = " La v a r i a b l e a v a l e " + a + " y l a v a r i a b l e           b vale
          " + b;
             // l a s c a d e n a s t a m b i é n s e pueden c o n c a t e n a r con o t r o s       tipos
                     de d a t o s ,
             // en c u y o c a s o e s o s v a l o r e s s e c o n v i e r t e n a c a d e n a s .   En
                     este
             // c a s o m e n s a j e q u e d a r í a como " La v a r i a b l e a v a l e 7 y        la
                     variable b
             // v a l e 3 . 0 "

     Con booleanos:
boolean s i = true ;
b o o l e a n no = f a l s e ;
boolean r e s u l t a d o ;
Primeros pasos con BeanShell                                                                                 33


r e s u l t a d o = ! s i ; // l a ! e s e l o p e r a d o r n o t ( n e g a c i ó n ) .
                // A p l i c a d o a t r u e , d e v u e l v e f a l s e , y a p l i c a d o a f a l s e ,
                // d e v u e l v e t r u e .
r e s u l t a d o = s i | | no ; // o p e r a d o r o r l ó g i c o .
                // D e v u e l v e t r u e s i a l menos uno de l o s d o s o p e r a n d o s
                // e s t r u e ( en e s t e c a s o d e v o l v e r í a t r u e ) .
r e s u l t a d o = s i && no ; // o p e r a d o r and l ó g i c o .
                // D e v u e l v e t r u e s ó l o cuando l o s d o s o p e r a n d o s s o n
                // t r u e ( en e s t e c a s o d e v o l v e r í a f a l s e ) .


   Los operadores se pueden combinar en expresiones complejas, utilizando pa-
réntesis si es necesario para definir el orden:
i n t d = a + b + c ; // suma de a , b y c
d = ( a + b ) ∗ c ; // sumar a y b , y m u l t i p l i c a r e l r e s u l t a d o p o r c
S t r i n g j u a n e s = a + a + a ; // " J u a n J u a n J u a n "
j u a n e s += j u a n e s ; // " J u a n J u a n J u a n J u a n J u a n J u a n "
b o o l e a n c o m p l e j o = ( s i && s i ) | | ( no | | no ) ; // e s t o da t r u e




2.1.4.        La estructura condicional (if)
    Hasta ahora, hemos visto cómo crear un método, escribir cosas en la pan-
talla o ventana del jugador y crear o actualizar variables. Estas instrucciones
se pueden combinar en secuencias para que se ejecuten unas después de otras;
pero con lo que de momento hemos visto, nuestro método siempre hará exac-
tamente lo mismo, una secuencia de operaciones predeterminadas. Esto limita
mucho el conjunto de cosas que podemos hacer. Para crear métodos más intere-
santes, necesitamos de alguna forma poder hacer que se comporten de manera
diferente según las circunstancias: por ejemplo, que el método parseCommand
que estamos definiendo actúe de manera distinta según el verbo que ha escrito
el jugador, o según la habitación en la que está, si ha realizado o no con an-
terioridad una determinada acción, o cualquier otra circunstancia que se nos
ocurra.
    Para conseguir estos comportamientos diferentes según las circunstancias,
podemos utilizar la estructura condicional, llamada if. La estructura condicional
nos permite definir un código que sólo se ejecuta si se cumple una determina-
da condición (por ejemplo, que el jugador esté en la habitación «cocina»), y,
opcionalmente, otro código que sólo se ejecuta si no se cumple la condición:
Mobile jugador = aCreature ;
i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) )
   j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a .  n" ) ;
else
   j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en o t r a p a r t e que no e s l a
             c o c i n a .  n" ) ;


    En general, la sintaxis de la instrucción if para ejecutar un código si y sólo
si se cumple una determinada condición es la siguiente:
    if ( condición ) cuerpo
    Donde el código de cuerpo sólo se ejecutará en el caso de que condición sea
cierta. En concreto, condición tiene que ser siempre una expresión que devuelva
un valor de tipo boolean (true o false). El código de cuerpo se ejecutará si el
valor de condición es true, y no se ejecutará si dicho valor es false.
34                                                                        Uso del lenguaje BeanShell


   En el caso de que el cuerpo del if esté formado por varias instrucciones, se
deben delimitar dichas instrucciones con llaves, como si fueran el cuerpo de un
método:
i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) )
{
   j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a .  n" ) ;
   j u g a d o r . w r i t e ( "Te dan g a n a s de p o n e r t e a c o c i n a r a l g o .  n" ) ;
}

    Si el cuerpo del if está formado por una única instrucción, se puede poner la
instrucción sin más, sin llaves:
i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) )
   j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a .  n" ) ;

     O bien ponerla con llaves como antes, que en este caso es equivalente:
i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) )
{
   j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a .  n" ) ;
}

    La sintaxis de la estructura if para ejecutar un código si se cumple una
condición y otro distinto si no se cumple es la siguiente:
    if ( condición ) cuerpo1 else cuerpo2
    De nuevo, cuerpo1 y cuerpo2 tienen que ir necesariamente entre llaves si
tienen más de una instrucción, y pueden ir sin llaves si tienen sólo una.
i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) )
{
   j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a .  n" ) ;
   j u g a d o r . w r i t e ( "Te dan g a n a s de p o n e r t e a c o c i n a r a l g o .  n" ) ;
}
else
   j u g a d o r . w r i t e ( "No e s t á s en l a c o c i n a .  n" ) ;

   Una estructura «if–else» se puede combinar con otras estructuras «if–else»
para dar una estructura «if–else if–else if...–else», como ésta:
i f ( e q u a l s ( v e r b , " comer " ) )
   j u g a d o r . w r i t e ( " Has p u e s t o e l v e r b o comer .  n" ) ;
else i f ( equals ( verb , " beber " ) )
   j u g a d o r . w r i t e ( " Has p u e s t o e l v e r b o b e b e r .  n" ) ;
else i f ( equals ( verb , " dormir " ) )
   j u g a d o r . w r i t e ( " Has p u e s t o e l v e r b o d o r m i r .  n" ) ;
else
   j u g a d o r . w r i t e ( "No e n t i e n d o e l v e r b o que h a s p u e s t o .  n" ) ;

    Este código escribe una cosa u otra en la consola del jugador según el valor
del parámetro verb del método.

Comparaciones
   Para decidir entre una rama u otra de una estructura condicional, necesita-
mos que nuestro código utilice alguna expresión o variable de tipo boolean, de
modo que ejecute la rama del if si esta expresión tiene un valor verdadero, y la
rama del else (o nada) si su valor es falso.
Primeros pasos con BeanShell                                                                                35


    ¿Cómo obtenemos expresiones de tipo boolean que sean relevantes para de-
finir nuestros métodos if? Existen muchas maneras, dependiendo de lo que uno
quiera hacer; pero una de las más básicas y comunes son las comparaciones.
Muchas veces queremos ejecutar un código si un valor es igual a otro (por ejem-
plo, si el valor de una variable es igual a un valor dado). Esto se consigue con
la función de comparación de igualdad equals.2
    La comparación de igualdad de AGE es una función equals al que se le pasan
dos parámetros que pueden ser de cualquier tipo (tipos básicos u objetos). La
función equals devuelve true si los dos parámetros que se le han pasado tienen
el mismo valor, y false si son distintos.
    Así, por ejemplo, podríamos hacer lo siguiente:
e q u a l s ( 3 , 4 ) ; // d e v u e l v e f a l s e
e q u a l s ( 3 , 3 ) ; // d e v u e l v e t r u e
e q u a l s ( 2 + 2 , 4 ) ; // d e v u e l v e t r u e
e q u a l s ( 2 + 2 , 5 ) ; // d e v u e l v e f a l s e
e q u a l s ( " F u l a n i t o " , " M e n g a n i t o " ) ; // d e v u e l v e f a l s e
String f = " Fulanito " ;
e q u a l s ( " F u l a n i t o " , f ) ; // d e v u e l v e t r u e
S t r i n g g = " Fula " ;
String h = " nito " ;
e q u a l s ( f , g ) ; // d e v u e l v e f a l s e
e q u a l s ( f , h ) ; // d e v u e l v e f a l s e
e q u a l s ( f , g+h ) ; // d e v u e l v e t r u e
e q u a l s ( room ( " C o c i n a " ) , room ( " C o c i n a " ) ) ; // d e v u e l v e t r u e
e q u a l s ( room ( " C o c i n a " ) , room ( " Baño " ) ) ; // d e v u e l v e f a l s e ( s a l v o que no
          e x i s t a n h a b i t a c i o n e s l l a m a d a s C o c i n a n i Baño , en c u y o c a s o s e
        c o n s i d e r a n i g u a l e s p o r q u e n i n g u n a de l a s d o s e x i s t e )

    Podemos ver un uso práctico de una comparación de igualdad en conjun-
ción con una estructura condicional si, en el método parseCommand visto con
anterioridad, queremos hacer que se responda de una manera determinada sólo
cuando el jugador escribe un determinado verbo. Por ejemplo:
v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s )
{
    i f ( e q u a l s ( v e r b , " comer " ) )
   {
       a C r e a t u r e . w r i t e ( "No p u e d e s comer a h o r a , que e s t á s a r é g i m e n .  n"
              );
       end ( ) ;
   }
}

   Con esto conseguimos que cuando el jugador use el verbo comer, se le diga
que está a régimen, sin cambiar el comportamiento de los otros verbos:
> inventario
Tienes una manzana.
> comer la manzana
No puedes comer ahora, que estás a régimen.
   2 Nota para programadores: BeanShell tiene otras comparaciones de igualdad por defecto,

que son el método equals de la clase Object y el operador ==. La función equals que se cubre
aquí es una función de más alto nivel creada a propósito para simplificar las comparaciones
en AGE, cubriendo los casos de uso más comunes en las aventuras. Los programadores que
tengan conocimientos de Java o de BeanShell pueden utilizar en su lugar las comparaciones
tradicionales con el método equals de Object y con ==, que por supuesto funcionan en AGE
como en Java.
36                                                                 Uso del lenguaje BeanShell


    Nótese que el end() está dentro del cuerpo del if, con lo cual sólo se impide
que AGE ejecute sus comportamientos estándar si realmente se usa el verbo
comer. Si hubiésemos puesto el end() fuera del cuerpo del if, haríamos que dejara
de funcionar el comando «inventario» (y cualquier otro) porque el end() se
ejecutaría siempre e impediría que AGE ejecutase sus comportamientos por
defecto. Si no hubiésemos puesto un end() en absoluto, ni siquiera dentro del if,
entonces al usar el verbo «comer» se imprimiría nuestro mensaje pero después
se seguiría procesando la entrada como si tal cosa, cosa que provocaría efectos
no deseados:

> comer la manzana
No puedes comer ahora, que estás a régimen.
¿Cómo? ¿Comer?

    En este caso, imprimimos el mensaje pero luego AGE procesa el comando, y
como por defecto no lo entiende (no está definido por defecto en AGE qué pasa
al comer algo), da un mensaje de error. Hay que tener cuidado, pues, de usar
los end() en los momentos en que se necesitan.
    Si en lugar de comprobar si dos cosas son iguales queremos comprobar si
son distintas, podemos utilizar el operador ! visto antes, que niega un valor
booleano. Así, equals(verb,"comer") devuelve true si y sólo si el parámetro
verb tiene como valor «comer»; mientras que !equals(verb,"comer") devuelve
true sólo si el valor del parámetro no es «comer».
    En el caso de trabajar con números (sean int o double), a menudo nos intere-
sará hacer comparaciones de superioridad y de inferioridad, en lugar de las de
igualdad. Es decir, querremos saber si un número es mayor o menor que otro.
Esto se hace con los operadores <, >, <= y >=:
boolean b ;
b = ( 4 > 3 ) ; // d e v u e l v e t r u e
b = ( 4 >= 3 ) ; // d e v u e l v e f a l s e
b = ( 4 >= 4 ) ; // d e v u e l v e t r u e
b = ( 4 . 2 > 3 . 5 ) ; // d e v u e l v e t r u e
b = ( 4 < 3 ) ; // d e v u e l v e t r u e
b = ( 3 < 4 ) ; // d e v u e l v e t r u e ;
i f ( x >= 0 ) a C r e a t u r e . w r i t e ( " E q u i s e s mayor que c e r o .  n" ) ; // p a r a
      e s t o t e n d r e m o s que h a b e r d e c l a r a d o a n t e s l a v a r i a b l e x




2.1.5.       Los bucles
    La estructura condicional (if–else) que hemos visto es una de las principales
estructuras de control, es decir, maneras de gestionar qué camino va siguiendo un
programa en BeanShell para ejecutar sus instrucciones. Las otras estructuras de
control importantes que necesitaremos para gestionar el flujo de los programas
son los bucles.
    Como hemos visto, una estructura condicional nos permite escoger entre un
código a ejecutar y otro según si se da o no una determinada condición. Este
código que se ejecuta lo hace únicamente una vez (salvo que estemos llamando
al if varias veces desde código externo a él, claro).
    Los bucles nos permiten ejecutar un bloque de código varias veces, repitién-
dose mientras una condición determinada se cumpla. El código del cuerpo del
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age
Documentacion age

Más contenido relacionado

La actualidad más candente

Introduccion poo con_java
Introduccion poo con_javaIntroduccion poo con_java
Introduccion poo con_javaRobert Wolf
 
Apunts dintel ligencia_artificial
Apunts dintel ligencia_artificialApunts dintel ligencia_artificial
Apunts dintel ligencia_artificialAndreu Garcia
 
39702397 matematicas-discretas
39702397 matematicas-discretas39702397 matematicas-discretas
39702397 matematicas-discretasGil Robles
 
MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...
MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...
MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...Carlos Vial
 
Algoritmos programacion-python
Algoritmos programacion-pythonAlgoritmos programacion-python
Algoritmos programacion-pythonLUIS COAQUIRA
 
Santana el arte_de_programar_en_r
Santana el arte_de_programar_en_rSantana el arte_de_programar_en_r
Santana el arte_de_programar_en_rVlad Crespo
 
El Arte de Programar en R
El Arte de Programar en REl Arte de Programar en R
El Arte de Programar en RHelio Colombe
 

La actualidad más candente (12)

Introduccion poo con_java
Introduccion poo con_javaIntroduccion poo con_java
Introduccion poo con_java
 
estructuras de datos
estructuras de datosestructuras de datos
estructuras de datos
 
Apunts dintel ligencia_artificial
Apunts dintel ligencia_artificialApunts dintel ligencia_artificial
Apunts dintel ligencia_artificial
 
39702397 matematicas-discretas
39702397 matematicas-discretas39702397 matematicas-discretas
39702397 matematicas-discretas
 
Algoritmos programacion-python
Algoritmos programacion-pythonAlgoritmos programacion-python
Algoritmos programacion-python
 
Grafi3
Grafi3Grafi3
Grafi3
 
MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...
MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...
MANUAL DE DISEÑO, CONSTRUCCIÓN, MANTENCIÓN Y MONITOREO DE TABLEROS DE MADERA ...
 
Algoritmos programacion-python
Algoritmos programacion-pythonAlgoritmos programacion-python
Algoritmos programacion-python
 
Santana el arte_de_programar_en_r
Santana el arte_de_programar_en_rSantana el arte_de_programar_en_r
Santana el arte_de_programar_en_r
 
El Arte de Programar en R
El Arte de Programar en REl Arte de Programar en R
El Arte de Programar en R
 
Manual
ManualManual
Manual
 
R manual
R manualR manual
R manual
 

Destacado

Documento presentacion reingsys_humano_2008_v_pub_def
Documento presentacion reingsys_humano_2008_v_pub_defDocumento presentacion reingsys_humano_2008_v_pub_def
Documento presentacion reingsys_humano_2008_v_pub_defReingsys
 
Acercándose a la entrega contínua cómo construir un build pipeline
Acercándose a la entrega contínua cómo construir un build pipelineAcercándose a la entrega contínua cómo construir un build pipeline
Acercándose a la entrega contínua cómo construir un build pipelineSoftware Guru
 

Destacado (6)

Documento presentacion reingsys_humano_2008_v_pub_def
Documento presentacion reingsys_humano_2008_v_pub_defDocumento presentacion reingsys_humano_2008_v_pub_def
Documento presentacion reingsys_humano_2008_v_pub_def
 
Redes
RedesRedes
Redes
 
Capítulo 6
Capítulo 6Capítulo 6
Capítulo 6
 
Acercándose a la entrega contínua cómo construir un build pipeline
Acercándose a la entrega contínua cómo construir un build pipelineAcercándose a la entrega contínua cómo construir un build pipeline
Acercándose a la entrega contínua cómo construir un build pipeline
 
Rentamos ltda
Rentamos ltdaRentamos ltda
Rentamos ltda
 
Educación para el desarrollo v2
Educación para el desarrollo v2Educación para el desarrollo v2
Educación para el desarrollo v2
 

Similar a Documentacion age

Libro programacion orientada_a_objetos_p
Libro programacion orientada_a_objetos_pLibro programacion orientada_a_objetos_p
Libro programacion orientada_a_objetos_ptonimur67
 
Libropoo
LibropooLibropoo
Libropooserimj
 
Desarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-javaDesarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-javaFreddy Quina
 
Libro javacontapa
Libro javacontapaLibro javacontapa
Libro javacontapaRobert Wolf
 
Libro javacontapa
Libro javacontapaLibro javacontapa
Libro javacontapaTabu Carlos
 
pensar_en_cpp-vol1.pdf
pensar_en_cpp-vol1.pdfpensar_en_cpp-vol1.pdf
pensar_en_cpp-vol1.pdfmacario17
 
Desarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-javaDesarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-javaVictor Basurto Alonso
 
Fundamentos de Programacion.pdf
Fundamentos de Programacion.pdfFundamentos de Programacion.pdf
Fundamentos de Programacion.pdfJorge Serran
 
Algoritmos y programacion_i_-_con_lengua
Algoritmos y programacion_i_-_con_lenguaAlgoritmos y programacion_i_-_con_lengua
Algoritmos y programacion_i_-_con_lenguaDarío Herrera
 
MANUAL DE LENGUAJE C
MANUAL DE LENGUAJE CMANUAL DE LENGUAJE C
MANUAL DE LENGUAJE Cclaudiocj7
 
Libro programación-en-c++
Libro programación-en-c++Libro programación-en-c++
Libro programación-en-c++Andres Escobar
 
Introduccion a la_programacion_con_c
Introduccion a la_programacion_con_cIntroduccion a la_programacion_con_c
Introduccion a la_programacion_con_cAbefo
 
El arte de programar en r
El arte de programar en rEl arte de programar en r
El arte de programar en rLuis Bautista
 

Similar a Documentacion age (20)

Libro programacion orientada_a_objetos_p
Libro programacion orientada_a_objetos_pLibro programacion orientada_a_objetos_p
Libro programacion orientada_a_objetos_p
 
Moolibro 110609124636-phpapp01
Moolibro 110609124636-phpapp01Moolibro 110609124636-phpapp01
Moolibro 110609124636-phpapp01
 
Libropoo
LibropooLibropoo
Libropoo
 
Desarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-javaDesarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-java
 
Libro javacontapa
Libro javacontapaLibro javacontapa
Libro javacontapa
 
Libro javacontapa
Libro javacontapaLibro javacontapa
Libro javacontapa
 
pensar_en_cpp-vol1.pdf
pensar_en_cpp-vol1.pdfpensar_en_cpp-vol1.pdf
pensar_en_cpp-vol1.pdf
 
Desarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-javaDesarrollo proyectos-informaticos-con-java
Desarrollo proyectos-informaticos-con-java
 
Pensar en cpp
Pensar en cpp Pensar en cpp
Pensar en cpp
 
Fundamentos de Programacion.pdf
Fundamentos de Programacion.pdfFundamentos de Programacion.pdf
Fundamentos de Programacion.pdf
 
Java2 d
Java2 dJava2 d
Java2 d
 
Java 2 d
Java 2 dJava 2 d
Java 2 d
 
Algoritmos y programacion_i_-_con_lengua
Algoritmos y programacion_i_-_con_lenguaAlgoritmos y programacion_i_-_con_lengua
Algoritmos y programacion_i_-_con_lengua
 
Documento_Diaz_de_Argandona_Ignacio
Documento_Diaz_de_Argandona_IgnacioDocumento_Diaz_de_Argandona_Ignacio
Documento_Diaz_de_Argandona_Ignacio
 
MANUAL DE LENGUAJE C
MANUAL DE LENGUAJE CMANUAL DE LENGUAJE C
MANUAL DE LENGUAJE C
 
Libro programación-en-c++
Libro programación-en-c++Libro programación-en-c++
Libro programación-en-c++
 
Introduccion a la_programacion_con_c
Introduccion a la_programacion_con_cIntroduccion a la_programacion_con_c
Introduccion a la_programacion_con_c
 
El arte de programar en r
El arte de programar en rEl arte de programar en r
El arte de programar en r
 
Manual LaTeX
Manual LaTeXManual LaTeX
Manual LaTeX
 
Hefesto v2.1
Hefesto v2.1Hefesto v2.1
Hefesto v2.1
 

Último

NARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFARO
NARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFARONARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFARO
NARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFAROJosé Luis Palma
 
DE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.ppt
DE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.pptDE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.ppt
DE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.pptELENA GALLARDO PAÚLS
 
el CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyz
el CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyzel CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyz
el CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyzprofefilete
 
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptxPPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptxOscarEduardoSanchezC
 
La triple Naturaleza del Hombre estudio.
La triple Naturaleza del Hombre estudio.La triple Naturaleza del Hombre estudio.
La triple Naturaleza del Hombre estudio.amayarogel
 
LINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptx
LINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptxLINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptx
LINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptxdanalikcruz2000
 
codigos HTML para blogs y paginas web Karina
codigos HTML para blogs y paginas web Karinacodigos HTML para blogs y paginas web Karina
codigos HTML para blogs y paginas web Karinavergarakarina022
 
Movimientos Precursores de La Independencia en Venezuela
Movimientos Precursores de La Independencia en VenezuelaMovimientos Precursores de La Independencia en Venezuela
Movimientos Precursores de La Independencia en Venezuelacocuyelquemao
 
Heinsohn Privacidad y Ciberseguridad para el sector educativo
Heinsohn Privacidad y Ciberseguridad para el sector educativoHeinsohn Privacidad y Ciberseguridad para el sector educativo
Heinsohn Privacidad y Ciberseguridad para el sector educativoFundación YOD YOD
 
DECÁGOLO DEL GENERAL ELOY ALFARO DELGADO
DECÁGOLO DEL GENERAL ELOY ALFARO DELGADODECÁGOLO DEL GENERAL ELOY ALFARO DELGADO
DECÁGOLO DEL GENERAL ELOY ALFARO DELGADOJosé Luis Palma
 
texto argumentativo, ejemplos y ejercicios prácticos
texto argumentativo, ejemplos y ejercicios prácticostexto argumentativo, ejemplos y ejercicios prácticos
texto argumentativo, ejemplos y ejercicios prácticosisabeltrejoros
 
Unidad II Doctrina de la Iglesia 1 parte
Unidad II Doctrina de la Iglesia 1 parteUnidad II Doctrina de la Iglesia 1 parte
Unidad II Doctrina de la Iglesia 1 parteJuan Hernandez
 
Introducción:Los objetivos de Desarrollo Sostenible
Introducción:Los objetivos de Desarrollo SostenibleIntroducción:Los objetivos de Desarrollo Sostenible
Introducción:Los objetivos de Desarrollo SostenibleJonathanCovena1
 
la unidad de s sesion edussssssssssssssscacio fisca
la unidad de s sesion edussssssssssssssscacio fiscala unidad de s sesion edussssssssssssssscacio fisca
la unidad de s sesion edussssssssssssssscacio fiscaeliseo91
 
MAYO 1 PROYECTO día de la madre el amor más grande
MAYO 1 PROYECTO día de la madre el amor más grandeMAYO 1 PROYECTO día de la madre el amor más grande
MAYO 1 PROYECTO día de la madre el amor más grandeMarjorie Burga
 
6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docx
6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docx6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docx
6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docxCeciliaGuerreroGonza1
 
programa dia de las madres 10 de mayo para evento
programa dia de las madres 10 de mayo  para eventoprograma dia de las madres 10 de mayo  para evento
programa dia de las madres 10 de mayo para eventoDiegoMtsS
 
La Función tecnológica del tutor.pptx
La  Función  tecnológica  del tutor.pptxLa  Función  tecnológica  del tutor.pptx
La Función tecnológica del tutor.pptxJunkotantik
 

Último (20)

NARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFARO
NARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFARONARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFARO
NARRACIONES SOBRE LA VIDA DEL GENERAL ELOY ALFARO
 
DE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.ppt
DE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.pptDE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.ppt
DE LAS OLIMPIADAS GRIEGAS A LAS DEL MUNDO MODERNO.ppt
 
el CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyz
el CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyzel CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyz
el CTE 6 DOCENTES 2 2023-2024abcdefghijoklmnñopqrstuvwxyz
 
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptxPPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
 
Defendamos la verdad. La defensa es importante.
Defendamos la verdad. La defensa es importante.Defendamos la verdad. La defensa es importante.
Defendamos la verdad. La defensa es importante.
 
La triple Naturaleza del Hombre estudio.
La triple Naturaleza del Hombre estudio.La triple Naturaleza del Hombre estudio.
La triple Naturaleza del Hombre estudio.
 
LINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptx
LINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptxLINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptx
LINEAMIENTOS INICIO DEL AÑO LECTIVO 2024-2025.pptx
 
codigos HTML para blogs y paginas web Karina
codigos HTML para blogs y paginas web Karinacodigos HTML para blogs y paginas web Karina
codigos HTML para blogs y paginas web Karina
 
Movimientos Precursores de La Independencia en Venezuela
Movimientos Precursores de La Independencia en VenezuelaMovimientos Precursores de La Independencia en Venezuela
Movimientos Precursores de La Independencia en Venezuela
 
Heinsohn Privacidad y Ciberseguridad para el sector educativo
Heinsohn Privacidad y Ciberseguridad para el sector educativoHeinsohn Privacidad y Ciberseguridad para el sector educativo
Heinsohn Privacidad y Ciberseguridad para el sector educativo
 
DECÁGOLO DEL GENERAL ELOY ALFARO DELGADO
DECÁGOLO DEL GENERAL ELOY ALFARO DELGADODECÁGOLO DEL GENERAL ELOY ALFARO DELGADO
DECÁGOLO DEL GENERAL ELOY ALFARO DELGADO
 
texto argumentativo, ejemplos y ejercicios prácticos
texto argumentativo, ejemplos y ejercicios prácticostexto argumentativo, ejemplos y ejercicios prácticos
texto argumentativo, ejemplos y ejercicios prácticos
 
Unidad II Doctrina de la Iglesia 1 parte
Unidad II Doctrina de la Iglesia 1 parteUnidad II Doctrina de la Iglesia 1 parte
Unidad II Doctrina de la Iglesia 1 parte
 
Introducción:Los objetivos de Desarrollo Sostenible
Introducción:Los objetivos de Desarrollo SostenibleIntroducción:Los objetivos de Desarrollo Sostenible
Introducción:Los objetivos de Desarrollo Sostenible
 
la unidad de s sesion edussssssssssssssscacio fisca
la unidad de s sesion edussssssssssssssscacio fiscala unidad de s sesion edussssssssssssssscacio fisca
la unidad de s sesion edussssssssssssssscacio fisca
 
La Trampa De La Felicidad. Russ-Harris.pdf
La Trampa De La Felicidad. Russ-Harris.pdfLa Trampa De La Felicidad. Russ-Harris.pdf
La Trampa De La Felicidad. Russ-Harris.pdf
 
MAYO 1 PROYECTO día de la madre el amor más grande
MAYO 1 PROYECTO día de la madre el amor más grandeMAYO 1 PROYECTO día de la madre el amor más grande
MAYO 1 PROYECTO día de la madre el amor más grande
 
6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docx
6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docx6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docx
6° SEM30 WORD PLANEACIÓN PROYECTOS DARUKEL 23-24.docx
 
programa dia de las madres 10 de mayo para evento
programa dia de las madres 10 de mayo  para eventoprograma dia de las madres 10 de mayo  para evento
programa dia de las madres 10 de mayo para evento
 
La Función tecnológica del tutor.pptx
La  Función  tecnológica  del tutor.pptxLa  Función  tecnológica  del tutor.pptx
La Función tecnológica del tutor.pptx
 

Documentacion age

  • 1. Aetheria Game Engine Documentación de AGE Cómo crear aventuras con Aetheria Game Engine Editor: Coordinador: Notxor Al-Khwarizmi Varios Autores versión de 15 de octubre de 2012
  • 2. Presentación de la documentación Estimado lector: Esta documentación pretende servir de guía y referencia para crear aventuras y otros juegos basados en texto para Aetheria Game Engine. Los juegos para AGE se crean mediante su herramienta de desarrollo, lla- mada PUCK (Playable Universe Construction Kit). Esta herramienta permite crear los elementos del mundo (habitaciones, cosas, criaturas...) y sus interac- ciones básicas mediante un entorno gráfico, sin necesidad de programar. Para conseguir comportamientos más complejos, dinámicos y personalizados, este en- torno gráfico se complementa con un lenguaje de programación (similar a Java) llamado BeanShell. Pero no te asustes: para aprender a crear juegos para AGE con este docu- mento no es necesario tener ningún conocimiento previo de programación. Todos los conceptos necesarios se explican desde cero, y crear juegos basados en texto con PUCK es más sencillo que crear otro tipo de programas. Por lo tanto, aun- que no sepas nada de programación, con esta guía estarás rápidamente creando tus propios mundos interactivos; y si ya sabes algo, podrás saltarte varias de las secciones introductorias. Esta versión en PDF de la documentación se ha generado a partir de la wiki (que está en http://www.caad.es/aetheria/doc/doku.php), gracias al traba- jo de Notxor, que ha maquetado el PDF. La documentación está en constante proceso de ampliación y mejora, y las actualizaciones irán apareciendo primero en la wiki para pasar después a sucesivas versiones de este fichero. No dudes dirigirme cualquier sugerencia o comentario, tanto como para me- jorar el contenido de la documentación como para mejorar el propio sistema, al email solrac888@yahoo.com. Atentamente, Al-Khwarizmi Creador de AGE
  • 3. Índice general 1. Uso básico de puck 8 1.1. Crear mundos con PUCK . . . . . . . . . . . . . . . . . . . . . . 8 1.2. Creación de Mundos para AGE con PUCK: Resumen . . . . . . 8 1.3. Primeros Pasos: Creando Habitaciones y Caminos . . . . . . . . . 10 1.3.1. Habitaciones y Caminos . . . . . . . . . . . . . . . . . . . 10 1.3.2. Creando un Personaje Jugador . . . . . . . . . . . . . . . 14 1.4. Seres inertes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.4.1. Descripciones de componentes . . . . . . . . . . . . . . . . 16 1.4.2. Cosas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2. Uso del lenguaje BeanShell 24 2.1. Primeros pasos con BeanShell . . . . . . . . . . . . . . . . . . . . 24 2.1.1. Los formularios de código . . . . . . . . . . . . . . . . . . 25 2.1.2. Los métodos . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.1.3. Variables y entrada/salida sencilla . . . . . . . . . . . . . 28 2.1.4. La estructura condicional (if) . . . . . . . . . . . . . . . . 33 2.1.5. Los bucles . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.1.6. Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . 40 2.2. Manipulación básica de entidades . . . . . . . . . . . . . . . . . . 41 2.2.1. Método de análisis de la entrada referida a una entidad . 41 2.2.2. Métodos para quitar, poner y mover entidades . . . . . . 43 2.2.3. Las variables self y world . . . . . . . . . . . . . . . . . . . 45 2.2.4. Métodos para comprobar dónde están las entidades . . . . 46 2.2.5. Método de análisis de la entrada referida a dos entidades 48 2.2.6. Variantes del método referido a dos entidades . . . . . . . 52 2.3. propiedades y relaciones . . . . . . . . . . . . . . . . . . . . . . . 55 2.3.1. Propiedades . . . . . . . . . . . . . . . . . . . . . . . . . . 55 2.3.2. Temporización y método update . . . . . . . . . . . . . . 56 2.3.3. Inicialización de propiedades . . . . . . . . . . . . . . . . 60 2.3.4. Relaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 2.4. Manejo de arrays y listas . . . . . . . . . . . . . . . . . . . . . . 64 2.4.1. Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 2.4.2. Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 2.5. Errores comunes con BeanShell . . . . . . . . . . . . . . . . . . . 72 2.5.1. Mensajes de error . . . . . . . . . . . . . . . . . . . . . . 72 2.5.2. Tipos de error comunes . . . . . . . . . . . . . . . . . . . 76 2.5.3. Funcionalidad de depuración . . . . . . . . . . . . . . . . 77
  • 4. 4 Índice general 3. Aspectos avanzados del modelo de mundo 80 3.1. Descripciones y nombres dinámicos . . . . . . . . . . . . . . . . . 80 3.1.1. Descripciones dinámicas . . . . . . . . . . . . . . . . . . . 81 3.1.2. Nombres dinámicos . . . . . . . . . . . . . . . . . . . . . . 82 3.2. Cosas abribles y cerrables . . . . . . . . . . . . . . . . . . . . . . 83 3.2.1. Definiendo cosas abribles y cerrables . . . . . . . . . . . . 83 3.2.2. Llaves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 3.2.3. Puertas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 3.2.4. Contenedores abribles y cerrables . . . . . . . . . . . . . . 87 3.3. Contenedores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 3.3.1. Definición y uso de contenedores . . . . . . . . . . . . . . 87 3.3.2. Acciones sobre objetos contenidos . . . . . . . . . . . . . 89 3.4. Miembros y prendas . . . . . . . . . . . . . . . . . . . . . . . . . 92 3.4.1. Miembros . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 3.4.2. Prendas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 3.5. Estados de las criaturas . . . . . . . . . . . . . . . . . . . . . . . 95 3.5.1. Las propiedades «state» y «target» . . . . . . . . . . . . . 96 3.5.2. Cambios de estado . . . . . . . . . . . . . . . . . . . . . . 98 3.5.3. Programación con estados . . . . . . . . . . . . . . . . . . 99 3.6. Combate y armas . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 3.6.1. Elementos de rol básicos . . . . . . . . . . . . . . . . . . . 100 3.6.2. Mecánica de combate . . . . . . . . . . . . . . . . . . . . 103 3.6.3. Armas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 3.6.4. Matemática de las armas . . . . . . . . . . . . . . . . . . 109 3.6.5. Esquivadas . . . . . . . . . . . . . . . . . . . . . . . . . . 112 3.6.6. Armaduras . . . . . . . . . . . . . . . . . . . . . . . . . . 113 3.6.7. Entrando en combate . . . . . . . . . . . . . . . . . . . . 113 3.7. Entidades abstractas . . . . . . . . . . . . . . . . . . . . . . . . . 114 3.8. Hechizos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 3.8.1. Creación de hechizos en PUCK . . . . . . . . . . . . . . . 116 3.8.2. Uso de hechizos por los jugadores . . . . . . . . . . . . . . 118 3.8.3. Funcionamiento de los hechizos . . . . . . . . . . . . . . . 120 3.8.4. Gestión de los puntos mágicos . . . . . . . . . . . . . . . . 126 3.8.5. Uso de hechizos por los personajes no jugadores . . . . . . 127 3.9. Mensajes por defecto . . . . . . . . . . . . . . . . . . . . . . . . . 128 3.9.1. Cambiar los mensajes por defecto . . . . . . . . . . . . . . 128 3.9.2. Generar dinámicamente los mensajes por defecto . . . . . 130 4. Métodos redefinibles 131 4.1. Eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 4.2. Otros métodos redefinibles . . . . . . . . . . . . . . . . . . . . . . 131 4.2.1. Métodos de Mobile (para PSIs) . . . . . . . . . . . . . . . 131 4.2.2. Ejemplo de uso . . . . . . . . . . . . . . . . . . . . . . . . 132 5. El análisis de la entrada 133 5.1. Métodos de análisis de la entrada (parseCommand) . . . . . . . . 134 5.1.1. Los métodos de análisis de la entrada . . . . . . . . . . . 134 5.1.2. Ejemplo de uso . . . . . . . . . . . . . . . . . . . . . . . . 134 5.1.3. Tipos de métodos de análisis de la entrada . . . . . . . . 135 5.1.4. El proceso de análisis de AGE . . . . . . . . . . . . . . . 137
  • 5. Índice general 5 5.2. Preprocesado de la entrada . . . . . . . . . . . . . . . . . . . . . 139 5.3. Gestión de verbos . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.3.1. Visualización de la lista de verbos por defecto . . . . . . . 141 5.3.2. Añadir y quitar verbos . . . . . . . . . . . . . . . . . . . . 142 5.3.3. Verbos adivinables y no adivinables . . . . . . . . . . . . 142 6. Presentación del mundo 145 6.1. Estilos de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 6.2. Prompt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 6.2.1. Métodos de manipulación del prompt . . . . . . . . . . . 146 6.2.2. Ejemplos de código . . . . . . . . . . . . . . . . . . . . . . 146 6.3. Tipografías en AGE . . . . . . . . . . . . . . . . . . . . . . . . . 147 6.3.1. Control básico de la tipografía . . . . . . . . . . . . . . . 147 6.3.2. Control avanzado de la tipografía . . . . . . . . . . . . . . 148 6.4. Métodos gráficos . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 6.4.1. Imágenes . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 6.4.2. Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 6.5. sonido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 6.5.1. Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 6.5.2. Música MIDI . . . . . . . . . . . . . . . . . . . . . . . . . 156 6.6. Otros aspectos de la presentación . . . . . . . . . . . . . . . . . . 158 7. Referencia de métodos invocables 159 7.1. Manipulación del modelo de mundo . . . . . . . . . . . . . . . . . 159 7.2. Obtención de nombres de cosas y criaturas . . . . . . . . . . . . . 159 7.2.1. Obtención de nombres para mostrar . . . . . . . . . . . . 159 7.3. Notificación de acciones y sucesos . . . . . . . . . . . . . . . . . . 162 7.3.1. Notificar sobre algo que ha ocurrido en una habitación . . 162 7.3.2. Notificar sobre algo que ha ocurrido con una cosa . . . . . 163 7.3.3. Notificar sobre algo que ha ocurrido con una criatura . . . 164 7.4. Ejecución automática de órdenes . . . . . . . . . . . . . . . . . . 164 7.4.1. Añadir una orden a la cola de órdenes . . . . . . . . . . . 165 7.4.2. Ejecutar una orden lo antes posible . . . . . . . . . . . . . 166 7.5. Presentación general . . . . . . . . . . . . . . . . . . . . . . . . . 168 7.6. Métodos útiles de la API de Java . . . . . . . . . . . . . . . . . . 168 8. Distribución como juego online 169
  • 7. Índice de figuras 1.1. Ventana de trabajo de puck. . . . . . . . . . . . . . . . . . . . . . 9 1.2. Iconos de puck. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3.1. Relación tiempo ataque y Habilidad . . . . . . . . . . . . . . . . 110 3.2. Relación tiempo ataque y Habilidad (real) . . . . . . . . . . . . . 111 3.3. Probabilidad de éxito en el combate . . . . . . . . . . . . . . . . 112 3.4. Diagrama del proceso de funcionamiento de un hechizo. . . . . . 121
  • 8. Capítulo 1 Uso básico de puck 1.1. Crear mundos con PUCK El PUCK (Playable Universe Construction Kit) es una herramienta gráfica de desarrollo que permite la creación de mundos interactivos para ser jugados con el Aetheria Game Engine. Estos mundos pueden utilizarse para jugar aventuras de texto, MUDs o juegos de rol mono y multijugador. En las siguientes secciones explicaremos detalladamente cómo se puede uti- lizar PUCK para crear un juego completo. Empezaremos con un resumen que nos dará una idea general de lo que tendremos que hacer, para luego entrar más específicamente en cada una de las etapas de creación de un mundo. En la figura 1.1 puedes ver un ejemplo de aventura en PUCK. 1.2. Creación de Mundos para AGE con PUCK: Resumen Un juego en Aetheria Game Engine viene dado por un mundo, y un mundo es una colección de diferentes objetos, que pueden ser de diversos tipos: Habitaciones (también llamadas localidades), que son lugares del mundo conectados entre sí por caminos. Una habitación puede representar literal- mente una dependencia de una casa; pero también podría ser, dependiendo de la ambientación, un cruce de caminos, una calle, etc. Personajes, que son seres vivos que pueblan el mundo, incluyendo al jugador, y que se pueden mover entre habitaciones a través de los caminos. Por ejemplo, tenderos, camareros, enemigos, animales, el propio jugador, etc. Cosas, que son seres inertes que se encuentran en las habitaciones o que llevan los personajes. Por ejemplo, puertas, llaves, cofres, sillas, mesas, espadas, dinero, etc. Para crear un juego completo, necesitaremos hacer las siguientes cosas (no necesariamente en orden):
  • 9. Creación de Mundos para AGE con PUCK: Resumen 9 Figura 1.1: Ventana de trabajo de puck. Crear los objetos del juego, Crear las relaciones entre ellos (por ejemplo, un camino es una relación entre dos habitaciones. O, si un personaje lleva un objeto, entonces el personaje y el objeto están relacionados mediante una relación «leva»), Dar a los objetos nombres y descripciones para que se muestren en el juego, Dotar a los objetos de comportamiento, es decir, que puedan reaccionar ante lo que hace el jugador y los demás objetos. El PUCK (Playable Universe Construction Kit) da soporte a todas estas actividades de la siguiente manera: La creación de objetos se hace en el editor gráfico que ocupa la parte iz- quierda de la ventana de PUCK. Las herramientas crear habitación, crear personaje y crear cosa permiten crear los objetos y colocarlos en el mundo: simplemente haz click sobre la herramienta correspondiente en la barra de herramientas, y a continuación lleva el objeto creado hasta el lugar del mundo en el que lo quieres poner. Nota: la representación gráfica del mun- do es simplemente una herramienta de conveniencia. El lugar del panel donde coloques un objeto no tendrá ninguna relevancia en el juego, así que simplemente colócalos como más cómodos te sean para verlos y ma- nipularlos. La creación de relaciones entre objetos se hace también en el editor gráfico, mediante las herramientas crear relación estructural y crear relación au- xiliar. Para crear una relación, basta con hacer click sobre la herramienta
  • 10. 10 Uso básico de puck Figura 1.2: Iconos de puck. correspondiente, y a continuación sobre los dos objetos que se desea rela- cionar. La representación gráfica de cada relación es una flecha. La descripción de los objetos se hace en los paneles de objeto que apare- cen en la parte derecha de la ventana de PUCK. Para acceder al panel de un objeto dado, basta con hacer click sobre él en la representación gráfi- ca cuando ninguna herramienta está seleccionada. Se nos mostrará toda la información de ese objeto (nombres, descripciones, etc.) y podremos modificarla. Por último, la descripción del comportamiento se hace también en los paneles de objeto. Ésta es la parte de la creación de un mundo en la que entra en juego la programación, para lo cual se utiliza el lenguaje de scripting BeanShell. El código para cada objeto se modifica en la ficha «Código y Propiedades» de su panel de objeto correspondiente. 1.3. Primeros Pasos: Creando Habitaciones y Ca- minos 1.3.1. Habitaciones y Caminos Veamos ahora cómo podemos usar PUCK para definir un mundo. Lo primero que haremos será crear un par de habitaciones unidas entre sí mediante un camino, de manera que el jugador pueda hacer algo como esto: >mirar
  • 11. Primeros Pasos: Creando Habitaciones y Caminos 11 Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor. Un precario puente de madera lo atraviesa, hacia el oeste. >ir hacia el oeste Atraviesas el puente hacia el oeste cuidadosamente. Las tablas de madera que lo forman crujen inquietantemente; pero llegas sano y salvo a la otra orilla. Te encuentras al oeste del gran río Pecos. Hay unos cuantos árboles altos a tu alrededor. Un tosco puente de madera lo atraviesa, hacia el este. >ir por el puente Atraviesas el puente hacia el este con sumo cuidado. Las tablas que lo componen emiten crujidos inquietantes; pero llegas sin incidencias a la otra orilla. Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrede- dor. Un precario puente de madera lo atraviesa, hacia el oeste. Para ello, lo primero que debemos hacer es ir al menú «Archivo – Nuevo», que nos creará un nuevo mundo en blanco para trabajar. Al hacer esto veremos a la izquierda el editor gráfico en blanco, que es donde colocaremos nuestros objetos; y a la derecha el panel de objeto asociado al mundo. En este panel aparece un formulario con una serie de propiedades del mundo. Es recomendable cubrir al menos el nombre corto y el nombre largo, que AGE utilizará para identificar el mundo. El nombre corto debería estar formado por una única palabra, aconsejablemente de no más de doce caracteres; mientras que el nombre largo puede ser un título de la longitud que se desee, y es lo que se mostrará al jugador como nombre de la aventura. El resto de campos (autor, versión, fecha...) son datos meramente informativos que se mostrarán al jugador cuando vaya a cargar el juego. Si queremos dejar estas propiedades para más tarde, o modificarlas en algún momento, es conveniente saber que podemos volver cuando queramos a este panel de mundo, simplemente seleccionando una zona vacía del editor gráfico. Pero pasemos a la acción: vamos a crear las dos habitaciones del ejemplo, situadas una al oeste de otra y separadas por un camino (puente). Para ello hacemos lo siguiente: Hacemos click en icono de la herramienta «añadir habitación» de la barra de herramientas. Movemos el cursor por el editor gráfico. Veremos que aparece un cuadrado (la habitación que estamos creando) que se mueve junto a nuestro cursor. Hacemos click, y la habitación quedará fija en el editor. A la derecha podremos ver su panel de objeto. Hagamos que esta habitación represente la orilla oeste del gran río Pecos. Para ello, cubrimos los campos del panel de objeto: • Donde pone «Nombre único», pondremos un nombre corto como por ejemplo «Oeste Pecos». Este nombre no se mostrará al jugador, se utiliza para identificar internamente la habitación en el juego y dis- tinguirla de las demás. Nosotros también lo utilizaremos cuando nos queramos referir a esta habitación en el futuro.
  • 12. 12 Uso básico de puck • Donde pone «Descripciones» irán las descripciones de la habitación, que son lo que se muestra al jugador cuando teclea «mirar» o cuando entra en la misma. Puede extrañarte que no haya una sola «Des- cripción», sino un campo para «Descripciones». Esto es porque las descripciones en AGE no son un texto estático, sino algo que puede variar según distintas condiciones (por ejemplo, la descripción de una localidad puede ser distinta según si es de día o de noche). El sistema que se utiliza para hacer posible esto es que la descripción que se muestra al jugador esté formada por distintos trozos que se pueden mostrar o no dependiendo de las condiciones que se den. En este ca- so, nos conformaremos con una descripción estática, con lo cual sólo necesitaremos uno de estos trozos, y sin ninguna condición asocia- da. Para ello, donde pone «Descripción» teclearemos la descripción completa de la habitación: Te encuentras al oeste del gran río Pecos. Hay unos cuantos árboles altos a tu alrededor. Un tosco puente de madera lo atraviesa, hacia el este. Y pulsamos el botón «Añadir». Vemos que la descripción introduci- da aparecerá en el cuadro «Descripciones», precedida de la palabra «Siempre». Esto último quiere decir que esta descripción se mostrará siempre que un jugador mire la habitación, es decir, no está sujeta a condición alguna. Por el momento no necesitamos añadir nada más a esta habitación. Es bueno saber que, si más tarde queremos modificar sus datos, basta con hacer click sobre su representación en el editor gráfico (cuando no estemos usando ninguna herramienta) para poder ver y modificar de nuevo su panel de objeto. Del mismo modo que creamos la habitación anterior, creamos una nueva para representar la orilla este del río. Para ello, tenemos que volver a hacer click en la herramienta «añadir habitación», ya que cada uso de la herra- mienta sirve para añadir una sola vez. Colocaremos la nueva habitación a la derecha de la anterior, dado que se encuentra al este. Si no hemos dejado espacio suficiente en el editor gráfico para colocarla, podemos utilizar las herramientas de desplazamiento y zoom: • Para usar la herramienta de desplazamiento, hacemos click sobre su icono en la barra de herramientas: A continuación, hace- mos un click sobre el editor gráfico, y movemos el cursor: los objetos del editor se desplazarán con él. Con otro click dejamos de usar la herramienta. • La herramienta zoom se utiliza del mismo modo. Después de hacer click en su icono y en el editor gráfico, podemos mover el ratón hacia arriba para alejar la vista o hacia abajo para acercarla.
  • 13. Primeros Pasos: Creando Habitaciones y Caminos 13 Rellenamos el nombre único y la descripción de la nueva habitación de la misma manera que lo habíamos hecho con la anterior, reflejando que estamos al este del Pecos. Ahora vamos a crear la conexión entre las dos habitaciones. Como po- demos ver en el texto de lo que queremos conseguir, las dos localidades deben estar unidas por un puente que cruza de este a oeste. El puente se debe poder cruzar en las dos direcciones; pero es importante saber que en AGE los caminos son de una sola dirección. Por lo tanto, para permitir el tránsito en las dos direcciones tenemos que crear dos caminos: uno de oeste a este y otro de este a oeste. Nótese que, aunque esto pueda parecer incómodo para casos simples, hace el sistema más poderoso, porque se puede dar tratamiento distinto a cada sentido del camino, incluyendo per- mitir el paso en un solo sentido, tener descripciones distintas para ambos, hacer que suceda algo al cruzar en un sentido dado, etc. Para crear los caminos, utilizaremos la herramienta «añadir relación es- tructural» de la barra de herramientas, que está identificada por este icono: Las relaciones en AGE son formas de expresar cualquier tipo de relación, permanente o temporal, entre dos objetos. Existen dos tipos de relaciones: relaciones estructurales y relaciones auxiliares. Las estructurales se llaman así porque son las que definen la estructura del mundo: nos dicen dónde están los objetos. También se caracterizan porque un objeto no tendría ningún sentido si no estuviese (o al menos pudiese estar) conectado al resto del mundo mediante relaciones estructurales. Las relaciones auxiliares se utilizan para definir otros aspectos de las interacciones entre objetos. Un camino se modela en AGE como una relación estructural entre una habitación y otra, de ahí que se cree con esta herramienta. Para crear un camino entre las dos habitaciones, seguimos los siguientes pasos: • Hacemos click sobre la herramienta «añadir relación estructural» • Hacemos click sobre la habitación que representa el Oeste del Pecos. • Hacemos click sobre la otra habitación. Veremos que aparece una flecha entre las dos habitaciones, que representa el camino que las une. Al igual que los objetos, podemos ver que las relaciones también tienen paneles de objeto. Nada más crear esta relación camino, podremos ver en la parte derecha de la ventana de PUCK su panel correspondiente. El panel tiene algunos campos ya cubiertos, como son las habitaciones origen y destino (que son las que marcamos en el mapa) y la dirección
  • 14. 14 Uso básico de puck estándar, que es un punto cardinal asociado al camino. Como habíamos colocado una habitación a la derecha de la otra, el camino aparecerá auto- máticamente marcado con la dirección estándar «este». Esto implica que se podrá utilizar con comandos como «ir al este». Si a pesar de haber colocado las habitaciones de esa manera éste no era el comportamiento que queríamos, podemos cambiar la dirección estándar (o quitarla para no tener ninguna) en el panel de objeto correspondiente al camino. Del mismo modo podríamos cambiar en cualquier momento las habitaciones origen y destino, podemos ver que para esto se utiliza el «nombre único» que hace referencia a cada habitación. Debajo de estos campos podemos ver una lista, inicialmente vacía, de co- mandos personalizados. En esta lista podemos introducir todas aquellas palabras que el jugador pueda usar para referirse a este camino además del punto cardinal dado por la dirección estándar. Como queremos que el jugador pueda teclear cosas como «ir puente» o «ir por el puente», añadi- mos «puente»: para ello, introducimos la palabra donde pone «Comando» y pulsamos el botón «Añadir». A continuación podemos ver un área para descripciones, que ya debería resultarnos familiar. Las descripciones para los caminos funcionan exacta- mente igual que para las habitaciones; pero se muestran cuando el jugador cruza el camino correspondiente. Así, para obtener el comportamiento que buscamos para este camino, debemos teclear en el campo «Descripción»: Atraviesas el puente hacia el este con sumo cuidado. Las tablas que lo com- ponen emiten crujidos inquietantes; pero llegas sin incidencias a la otra orilla. Con esto tenemos todo lo que necesitábamos por el momento para este camino. Cuando volvamos a necesitar modificar este panel de objeto, basta con que hagamos click sobre la flecha que representa el camino en el mapa para acceder a él. Para crear el otro camino, como es imaginable, basta con repetir el mismo proceso; pero haciendo click primero sobre la habitación del este y luego sobre la del oeste. Nos aparecerá otra flecha en dirección opuesta, que no se solapa con la anterior para que podamos hacer click fácilmente en cualquiera de ellas accediendo a su correspondiente panel de objeto. La descripción y el comando personalizado se introducen del mismo modo. 1.3.2. Creando un Personaje Jugador Con esto ya hemos creado un mínimo mundo con el que jugar; pero nos falta un elemento necesario para que la aventura tenga sentido: un personaje que pue- da recorrerlo. En AGE, los jugadores están en la piel de personajes que habitan en el mundo e interactúan con él (aunque también pueden crearse personajes que no sean jugadores). Por lo tanto, incluso en un juego para un solo jugador deberemos poner al menos un personaje que represente a ese jugador para que se pueda jugar. Para ello, utilizaremos la herramienta «añadir personaje» de la barra de herramientas:
  • 15. Primeros Pasos: Creando Habitaciones y Caminos 15 Y haremos lo siguiente: Para usar esta herramienta, procedemos de la misma manera que cuando añadimos habitaciones al mundo: hacemos click sobre su icono en la ba- rra de herramientas, deslizamos el cursor por el editor gráfico y hacemos click sobre el punto en que queremos dejar al personaje. Será conveniente que lo coloquemos cerca de la habitación donde queremos que el jugador aparezca al principio del juego; pero –ojo, importante– no dentro de ella. Esto es porque en el editor gráfico el hecho de que algo esté dentro de una habitación no se representa colocando su icono dentro de la misma; sino uniendo la habitación a ese algo mediante una relación estructural. Representar unas cosas dentro de otras podría parecer más natural a sim- ple vista; pero resultaría engorroso cuando una habitación contuviese gran número de personajes o cosas. Así pues, el siguiente paso será crear la relación estructural entre la ha- bitación (que puede ser la oeste o la este, dependiendo de dónde queréis que empiece el personaje: lo que creamos con PUCK es siempre el estado inicial del mundo, que luego podrá cambiar durante el juego cuando los personajes se muevan y manipulen los objetos) y el personaje. Para ello, utilizamos la herramienta «crear relación estructural» que ya conocemos: y hacemos click primero sobre la habitación y luego sobre el personaje (el orden es importante). Esto nos creará una relación estructu- ral de tipo «contiene» que significa que la habitación contiene al personaje, y que, al contrario que la relación «camino» que veíamos antes, no tiene nada que configurar. Para que todo funcione, sólo falta una cosa: especificar que el personaje que hemos creado es un jugador. Para ello, hacemos click sobre él para obtener su panel de objeto, y marcamos la casilla que dice «jugador». Esto hace que, cuando alguien arranque la aventura, el AGE lo ponga en la piel de este personaje (en juegos multijugador las cosas son algo más complicadas; pero ya las veremos). Si hurgamos en el panel de objeto asociado al personaje podemos ver que tiene diversos datos configurables, como por ejemplo nombre único y descripciones. Estas últimas funcionan del mismo modo que las de las habitaciones y caminos, y en este caso se mostrarían si el jugador se mirase a sí mismo. Puedes cubrirlas si quieres; aunque no son necesarias para el comportamiento que queríamos. Ahora sí que tenemos un mundo de AGE completo y jugable (aunque, de momento, no muy emocionante). Para jugarlo, no tenemos más que hacer click en la herramienta Ejecutar mundo:
  • 16. 16 Uso básico de puck La herramienta nos recuerda que para probar la aventura tiene que guardar el fichero (lo hará automáticamente) y nos da a elegir entre dos interfaces de eje- cución: el SDI (ventana simple) o el MDI (ventana con sub–ventanas). Podemos escoger cualquiera de los dos; aunque para propósitos de prueba de aventuras de un solo jugador el SDI suele resultar suficiente y más sencillo. Después, le damos al botón Aceptar para ejecutar la aventura. Si lo hemos hecho todo bien, podremos jugar la partida que hemos visto al principio de la sección. No se puede decir que haya sido difícil, ¿verdad? Pues ahora vamos a mejo- rarlo. 1.4. Seres inertes 1.4.1. Descripciones de componentes En la sección 1.3, hemos visto algunos conceptos básicos de PUCK y hemos definido un mundo rudimentario con un par de habitaciones y caminos. Por el momento, lo único que este mundo permite hacer al jugador es desplazarse de una habitación a otra a través de los caminos; pero la interacción con el mundo no va mucho más allá. Por ejemplo: >mirar Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor. Un precario puente de madera lo atraviesa, hacia el oeste. >mirar los árboles ¿Qué pretendes mirar? >mirar el puente ¿Qué pretendes mirar? Parece que una primera característica deseable para mejorar la interacción del jugador con el mundo sería que se pudiesen mirar los objetos que apare- cen mencionados en las descripciones. Así, nos gustaría que cuando el jugador pusiese «mirar los árboles», apareciese una descripción de los mismos para dar ambientación. La forma más sencilla de conseguir esto en AGE mediante las llamadas descripciones de componentes o descripciones extra. Las descripciones de componentes pueden añadirse a casi cualquier objeto del mundo (incluyendo habitaciones, personajes, cosas, etc.) y siguen siempre el mismo sistema, que es una extensión del que seguían las descripciones convencionales que hemos visto. Así, si en la sección anterior veíamos que las descripciones convencionales eran realmente listas de descripciones, cada una de las cuales tenía asociada una condición (que por el momento habíamos dejado en blanco para que se mostraran siempre) y un texto; las descripciones extra también serán listas de descripciones; pero cada una tendrá asociada una serie de nombres, una condición y un texto. Si añadimos una descripción extra a una localidad y el jugador teclea «mirar ‘algo’» (o alguna frase sinónima) en ella, entonces se mostrará la descripción si ese ‘algo’ coincide con uno de los nombres y además la condición asociada se cumple.
  • 17. Seres inertes 17 Vamos a hacer que el jugador pueda mirar los árboles y el puente desde la localidad oeste. Para ello, hacemos click sobre esta localidad en el editor grá- fico, y nos aparece su panel de objetos. Debajo de la sección de descripciones convencionales que ya tenemos cubierta, vemos la sección «Descripciones de componente». En el campo «Nombres de ref. sep. por comas» tecleamos, sin las comillas: «árbol,árboles»; y en el campo «Descripción» ponemos lo que quere- mos que le aparezca al jugador cuando mire los árboles, como puede ser «Son unos árboles muy verdes y muy bonitos.» Como en ocasiones anteriores, dejamos el campo «Condición» vacío, ya que esta descripción no dependerá de ninguna condición externa, y pulsamos el botón «Añadir». En la lista de descripciones extra veremos algo como «árbol,árboles: Siempre: Son unos árboles muy verdes y muy bonitos», donde se muestran los nombres y la descripción; y la palabra «Siempre» indica que la descripción va a mostrarse siempre que el jugador mire, sin depender de ningún otro factor. Lo mismo podemos hacer con el puente si añadimos una descripción extra con nombre «puente» y descripción «Es un precario puente de madera.» o cualquier texto similar. Si queremos que el puente se vea desde las dos localidades, como sería lógico, tenemos que poner su descripción extra en ambas. 1.4.2. Cosas Las descripciones de componentes proporcionan una primera manera de ha- cer el mundo más interesante y llegar un poco más allá de las habitaciones y caminos; pero tienen sus limitaciones. Las descripciones de componentes nos permiten definir elementos del mundo que los jugadores pueden mirar; pero la posible interacción con ellos se reduce sólo a eso: a mirar. A la hora de crear un juego decente, esto seguramente no sea suficiente. Nos interesan objetos físicos con los que los jugadores puedan interactuar de más maneras: cogerlos, llevarlos en su inventario, dejarlos en alguna otra parte, y seguramente hacer más cosas dependiendo del tipo de objeto que sea. Este tipo de objetos físicos son lo que en AGE denominamos «cosas». Para probar las cosas, vamos a crear una piedra que el jugador pueda al menos coger, llevar y dejar. En capítulos posteriores del tutorial veremos cómo hacer cosas más complejas (por ejemplo que puedan abrirse y cerrarse, llevar otras cosas dentro, etc.); pero por el momento empezaremos por lo básico. Creación de cosas Al contrario que las descripciones extra, las cosas son objetos de pleno dere- cho en AGE, y tienen una representación gráfica en el editor del PUCK. Para añadir una cosa, utilizamos la herramienta «añadir cosa»: A la hora de utilizar esta herramienta, procedemos de manera análoga a cuando habíamos añadido un personaje al mundo: hacemos click sobre el icono de «añadir cosa», movemos el cursor por el editor gráfico hasta dejarlo en la ubicación deseada para el objeto (que no debe coincidir con la habitación en la que queremos ponerlo; aunque sí es conveniente que esté cerca), y hacemos click
  • 18. 18 Uso básico de puck sobre esa ubicación. Para colocar la cosa en una localidad, igual que habíamos hecho con el personaje, creamos una relación estructural: hacemos click en la herramienta «crear relación estructural» y a continuación en la habitación y en la cosa, por ese orden. Esto creará una relación «contiene» entre habitación y cosa que indica que la cosa está situada en dicha habitación. Características básicas de cosas Una vez que tenemos nuestra cosa creada y vinculada a una habitación, ha- cemos click en su icono del editor gráfico para ver su panel de objeto. Los paneles de objeto de las cosas son algo más complicados que los de las habitaciones; pero algunos de sus componentes nos resultarán familiares, y otros los aprenderemos fácilmente. En primer lugar podemos ver el campo para el nombre único, que funciona igual que el de las habitaciones, sirviendo para distinguir internamente el objeto. En este punto es conveniente aclarar que los nombres únicos deben ser realmente únicos, es decir, no debe haber en un mundo dos objetos con el mismo nombre único, ni siquiera si son objetos de tipos completamente distintos. Esto quiere decir que no debes ponerle a una cosa un nombre que hayas utilizado para, por ejemplo, una habitación. A nuestro objeto podemos llamarle «Piedra». Bajo el nombre único, debajo de unos campos «Heredar de:» y «Ejemplo de:» que no veremos por el momento, podemos ver un campo de «Género», que nos da a elegir entre masculino y femenino. El género de una cosa es el género que tiene en castellano el nombre de esa cosa, y se utiliza para construir los textos del juego. Si pusiésemos que la piedra es «Masculino», podríamos obtener textos en el juego como «aquí hay un piedra» o «coges el piedra del suelo», así que es importante cubrir bien este campo si queremos un mundo que hable decentemente el idioma. Debajo del género, podemos ver unos campos para el «Peso» y el «Volumen» de la cosa que, como es imaginable, representan el peso y el volumen que tiene el objeto en el mundo virtual que estamos creando. Aunque se pueden utilizar para más cosas, la consecuencia más inmediata de estos valores es que un personaje no podrá llevar consigo objetos que superen el máximo peso y volumen que pueda acarrear. Si en tu juego no quieres prestar atención a esos detalles, simplemente puedes dejar el peso y el volumen de todos los objetos a cero. En este caso podemos poner, por ejemplo, peso y volumen 5. Después de los campos correspondientes al peso y el volumen, hay en el formulario dos opciones llamadas «Contenedor» y «Fijo en el sitio». La opción «Contenedor» puede marcarse para representar cosas que puedan tener otras cosas dentro, como una bolsa o un baúl.1 La opción «Fijo en el sitio» denota un 1 El autor de AGE recomienda a título personal no usar los contenedores en juegos más de lo estrictamente necesario, pues tienden a complicar innecesariamente la vida al jugador al tener que preocuparse de sacar y meter objetos de dentro de otros, cosa que puede ser interesante cuando es parte del argumento de la aventura (encontrar la llave de un antiguo baúl, etc.) pero no aporta mucho si se usa como elemento de ambientación.
  • 19. Seres inertes 19 objeto que no se puede coger, como una farola o una montaña; todas las cosas que no tengan esta opción marcada serán por defecto susceptibles de ser cogidas por los jugadores. En el caso de la piedra, lo lógico será no marcar ninguna de las dos opciones, ya que una piedra no puede contener otras cosas en su interior, y queremos que el jugador la pueda coger. A continuación están las descripciones y las descripciones de componentes, que se rellenan de la misma manera que en las habitaciones. Las descripcio- nes en este caso aparecerán cuando un jugador ponga «mirar ‘nuestra cosa’», y funcionarán tanto si el jugador lleva consigo la cosa como si simplemente está en la misma localidad. Las descripciones de componentes se pueden usar para describir partes o características de los objetos: por ejemplo, si nuestro objeto es una linterna, podemos usar una descripción extra para describir el botón de encendido de la linterna. Si ponemos como nombre para la descripción de com- ponente «botón», y nuestra linterna respondía al nombre «linterna», el jugador podrá ver la descripción extra tecleando «mirar el botón de la linterna». Noso- tros nos limitaremos a añadir una descripción convencional para la piedra, algo como: «Es una piedra estándar, de las de toda la vida. Podrías abrir cabezas con ella.» Nombres para mostrar y nombres de referencia Todo lo mencionado está en la ficha «General» del panel de objeto, que es la que hemos visto hasta ahora en todos los objetos que hemos creado. Sin embargo, puede que ya te hayas fijado en que algunos de ellos tienen más fichas aparte de ésta, y es el caso de nuestra recién creada piedra. Ahora vamos a ir a la segunda ficha, llamada «Nombres». Cubrir esta ficha es esencial para crear una cosa, porque nos permite definir el nombre o nombres de dicha cosa. Hasta ahora, en la ficha «General» del panel habíamos visto el «Nombre único» de la cosa, que nos servía para identificarla. Pero, como ya mencionamos al hablar de habitaciones, los nombres únicos de los objetos sólo se usan para que los distinga el creador del juego y el propio juego; sin que se muestren en ningún caso al jugador. Por lo tanto, tendremos que definir otros nombres (que pueden coincidir o no con el nombre único) para mostrar al jugador y para que el jugador pueda interactuar con la piedra. En la ficha «Nombres» podemos ver espacio para poner cuatro tipos de nom- bres: «Nombres singulares para mostrar», «Nombres plurales para mostrar», «Nombres singulares de referencia» y «Nombres plurales de referencia». Los dos primeros tipos son los nombres que se mostrarán al jugador, y fun- cionan exactamente igual que las descripciones. Si queremos que el objeto se llame siempre de una manera determinada y ya está, basta con que tecleemos su nombre en el campo «Nombre:» de «Nombres singulares para mostrar» y pulsemos «Añadir». En nuestro caso, si añadimos de esta manera el nombre «piedra», esto se traducirá en el juego a textos como «aquí puedes ver una piedra», «coges la piedra» «dejas la piedra», «llevas una piedra»... Si quisiése- mos que el nombre de un objeto cambiase según circunstancias del juego (por ejemplo, la piedra podría convertirse en una «piedra mojada» si le echásemos agua por encima), tendríamos que añadirle más nombres singulares y asociarles diferentes condiciones. Nosotros nos conformaremos con un nombre estático, así que añadimos «piedra» sin especificar condición alguna. Los «Nombres plurales para mostrar» se utilizan para mostrar al jugador
  • 20. 20 Uso básico de puck si hay varios objetos iguales en un mismo sitio. Por ejemplo, para que el juego pudiese construir frases como «llevas dos piedras» o «aquí hay tres piedras», tendríamos que añadir «piedras» como nombre plural. Si no va a haber varios objetos iguales en el juego que se puedan agrupar de esta manera, como es nuestro caso, podemos dejar los nombres plurales en blanco. Más adelante ve- remos cómo se pueden crear varios objetos idénticos que se puedan agrupar, y utilizaremos estos nombres plurales. Los «Nombres singulares de referencia» son aquellos nombres por los cuales el jugador se puede referir al objeto. Estos nombres no se muestran en la aventura; pero serán los que el sistema utilice para saber que el jugador se ha referido en su orden a un objeto dado. Como al jugador puede ocurrírsele referirse a una cosa usando una palabra que no sea el nombre que se le muestra en pantalla, suele ser recomendable incluir sinónimos en los nombres de referencia. Por ejemplo, en este caso podemos añadir los siguientes nombres de referencia para la piedra: «piedra», «roca» y «pedrusco». Después de teclear cada nombre en el campo «Nombre», pulsamos el botón «Añadir» para colocarlos en la lista, o podemos pulsar «Cambiar» para modificar alguno si nos hemos equivocado. De este modo, el jugador podrá referirse a la piedra mediante comandos como «coger piedra», «dejar roca» o «mirar pedrusco», y todos serán entendidos como referidos a nuestro objeto piedra. En los «Nombres plurales de referencia» pondremos los nombres por los cuales el jugador se puede referir a un conjunto de objetos que incluya éste. Normalmente, tendremos aquí las versiones de los nombres singulares de refe- rencia: en este caso «piedras», «rocas» y «pedruscos». De esta forma, si hay varias piedras (todas con esos nombres de referencia) y el jugador pone «coger las piedras» o «coger todas las rocas», su orden se ejecutará sobre todas ellas. Un truco que suele venir bien, y podemos hacer en este caso, es poner como último nombre plural de referencia «todo». De esta manera, cuando el jugador ponga «coger todo», su orden actuará sobre todos los objetos que tengan ese nombre plural de referencia. Interacciones básicas con las cosas Una vez rellenados de este modo los nombres para mostrar y de referencia de nuestra piedra, podemos utilizar la herramienta «Ejecutar mundo» para probar el objeto que hemos creado. Deberíamos ser capaces de hacer estas cosas: >mirar Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor. Un precario puente de madera lo atraviesa, hacia el oeste. Aquí hay una piedra. >mirar los árboles Son unos árboles muy verdes y muy bonitos. >mirar la piedra Es una piedra estándar, de las de toda la vida. Podrías abrir cabezas con ella. >coger la roca Coges la piedra. Es una piedra estándar, de las de toda la vida. Podrías abrir cabezas con ella. >inventario Tienes una piedra. >dejar todo
  • 21. Seres inertes 21 Dejas la piedra. >inventario No tienes nada. >mirar Te encuentras al este del gran río Pecos. Hay muchos árboles bajos a tu alrededor. Un precario puente de madera lo atraviesa, hacia el oeste. Aquí hay una piedra. Cosas con el mismo nombre de referencia Como hemos visto, los nombres de referencia nos determinan cómo el jugador se puede referir a una cosa. Pero a veces podría darse el caso de que varias cosas compartan un mismo nombre de referencia. Por ejemplo, supongamos que hemos definido las siguientes dos cosas: Una piedra blanca, que tiene como nombre para mostrar «piedra blan- ca», y como nombres de referencia «piedra blanca», «pedrusco blanco», «piedra», «pedrusco». Una piedra negra, que tiene como nombre para mostrar «piedra negra», y como nombres de referencia «piedra negra», «pedrusco negro», «piedra», «pedrusco». En este ejemplo, hemos puesto «piedra» como nombre de referencia de ambas piedras para que cuando el jugador encuentre una de ellas pueda simplemente teclear comandos como «coger piedra» y funcionen, sin especificar el color: Aquí hay una piedra blanca. >coger la piedra Coges la piedra blanca. Sin embargo, ¿qué pasará si el jugador teclea «coger la piedra» en una habi- tación donde está tanto la piedra blanca como la negra? ¿Cuál de ellas cogerá? La respuesta es que los nombres de referencia tienen una prioridad corres- pondiente a la posición que ocupan en la lista de nombres de referencia de PUCK (posición más alta quiere decir mayor prioridad). Cuando un jugador teclea una orden, las palabras que siguen al verbo se comparan con los nombres de referencia de los objetos que están al alcance del jugador, seleccionándose aquellos nombres de referencia que aparezcan mencionados en las palabras te- cleadas. En el caso de que haya un único nombre de referencia seleccionado de este modo (o varios, pero todos pertenecientes a la misma cosa), la acción se ejecuta sobre la cosa que tiene ese nombre. En el caso de que se seleccionen nombres de referencia de diferentes cosas, la acción se ejecuta sobre aquélla a la que perteneza el nombre de referencia de mayor prioridad (es decir, el que aparece más arriba en la lista) de entre los seleccionados. En el caso de que haya un empate a prioridades, se ejecuta sobre un objeto cualquiera. Por ejemplo, si en el caso de las piedras blanca y negra hemos introducido los nombres de referencia en el orden especificado arriba, las prioridades para la piedra blanca serían: Prioridad 1. piedra blanca Prioridad 2. pedrusco blanco
  • 22. 22 Uso básico de puck Prioridad 3. piedra Prioridad 4. pedrusco Y para la piedra negra serían: Prioridad 1. piedra negra Prioridad 2. pedrusco negro Prioridad 3. piedra Prioridad 4. pedrusco Si el jugador teclea «coger la piedra blanca», en la orden tecleada aparecen nombres de prioridad 1 y 3 de la piedra blanca (aparece «piedra blanca», de prioridad 1, pero también aparece «piedra», de prioridad 3, como parte de la cadena). Sin embargo, de la piedra negra, sólo aparece un nombre de prioridad 3 («piedra»). Como la prioridad 1 le gana a la prioridad 3, el jugador cogerá la piedra blanca. Si el jugador teclea «coger el pedrusco negro», en la orden aparece un nombre de prioridad 4 de la piedra blanca («pedrusco») y nombres de prioridad 2 y 4 de la piedra negra («pedrusco negro» y «pedrusco»). Como la prioridad 2 es mayor que la prioridad 4, el jugador cogerá la piedra negra. ¿Qué pasa si el jugador teclea simplemente «coger una piedra»? En este caso para ambos objetos se seleccionaría un nombre de prioridad 3 («piedra»). Como hay empate a prioridades, el jugador cogería una piedra cualquiera: se supone que ambas se ajustan por igual a la orden dada por el jugador, así que si sólo ha especificado «coger una piedra», debería servirle cualquiera de los dos. Si por algún motivo quisiéramos asegurarnos de que con esta orden el jugador siempre cogiese una piedra dada (por ejemplo, la blanca); tendríamos que hacer que el nombre de referencia «piedra» tuviese más prioridad en esa piedra que en la otra. En general, para que este sistema de prioridades para los nombres de referen- cia nos conduzca a una interpretación natural de las órdenes de los jugadores, lo único que tendremos que hacer es poner los nombres más específicos por en- cima de los más genéricos (tal y como hemos hecho en el ejemplo de la piedra). Entrando más en detalle, lo que necesitamos es que si un nombre de referencia es específico de un objeto, tenga más prioridad que los nombres más genéricos de otros objetos que puedan entrar en conflicto con ese nombre específico. Por ejemplo, si el nombre específico «piedra blanca» tuviera prioridad 3 en la piedra blanca y el nombre genérico «piedra» tuviera prioridad 1 en la piedra negra, tendríamos problemas, porque al «coger la piedra blanca» ganaría la piedra negra al tener el nombre genérico «piedra» con más prioridad que el nombre específico «piedra blanca» de la piedra blanca. Sin embargo, casos como éste prácticamente nunca se podrán dar si seguimos la norma general de que, dentro de cada cosa, los nombres específicos aparecen antes que los genéricos. Siguien- do esta simple regla, normalmente no hará falta acordarse de cómo funciona el sistema de prioridades salvo para casos avanzados en los que se quiera tener un control muy detallado de las maneras de referirse a cada objeto. Nótese que, si en lugar de nombres singulares de referencia hablamos de nombres plurales de referencia, con estos últimos la acción no se ejecutará sobre
  • 23. Seres inertes 23 un solo objeto, sino con todos los que tengan un nombre plural de referencia seleccionado. Es decir, si las dos piedras del ejemplo tienen como nombre plural de referencia la palabra «piedras», entonces la orden «coger las piedras» hará que el jugador coja ambas, independientemente de las prioridades.
  • 24. Capítulo 2 Uso del lenguaje BeanShell Los formularios de PUCK, como los vistos en el capítulo anterior, propor- cionan una manera sencilla de construir un mundo con diferentes localizaciones y objetos que los jugadores puedan manipular; sin necesidad de escribir código en ningún lenguaje de programación. Sin embargo, si queremos conseguir mun- dos complejos donde las entidades exhiban comportamientos dinámicos y donde podamos definir acciones personalizadas que vayan más allá de los comporta- mientos por defecto, sí que necesitaremos programar. Para estas definiciones de comportamientos complejos que requieren progra- mación, AGE utiliza el lenguaje BeanShell. BeanShell es un lenguaje de scripting muy parecido a Java. De hecho, la sintaxis de Java se puede utilizar tal cual en BeanShell; pero éste además permite usar variables con tipado dinámico y tiene otras características donde «relaja» los requisitos de Java. Para añadir código BeanShell a un mundo con PUCK, se puede ir a la pesta- ña «Código y Propiedades» de cualquier entidad (las entidades son los objetos del mundo representados por iconos que añadimos en el mapa de PUCK, como habitaciones, cosas y criaturas) o bien del propio mundo, y nos aparecerá un área de texto (con un botón «Ampliar» que la convierte en una ventana inde- pendiente) para introducir el código. AGE es un sistema orientado a objetos, de modo que el código que modifique el comportamiento de una entidad determina- da deberá introducirse en el campo de código de esa entidad. El campo de código del mundo permite hacer modificaciones más globales en el comportamiento de la aventura. A lo largo de las secciones de este capítulo veremos una introducción a cómo programar en BeanShell para crear aventuras en AGE. Esta información se ampliará en subsiguientes capítulos, donde la entremezclaremos con más cosas que se pueden hacer en los formularios de PUCK; ya que ambas cosas no son independientes sino que hay aspectos de PUCK que hacen uso o interactúan con el código BeanShell, haciendo necesario tratarlas de forma entrelazada. 2.1. Primeros pasos con BeanShell BeanShell es un lenguaje orientado a objetos, basado en Java, que se utiliza para definir comportamientos avanzados en entidades y mundos de AGE. En ésta y las siguientes secciones, describiremos cómo se puede usar BeanShell
  • 25. Primeros pasos con BeanShell 25 para este propósito. Esto quiere decir que no veremos exhaustivamente todas las características de BeanShell, sino que sólo describiremos lo necesario para utilizarlo en AGE de forma lo más sencilla posible. Los programadores que quieran un conocimiento más completo y riguroso de BeanShell, incluyendo todas sus características y no limitado a AGE, pueden consultar su página web http://www.beanshell.org. 2.1.1. Los formularios de código En los formularios de «Código y propiedades» de PUCK se puede escribir código BeanShell. Este código puede estar asociado a una entidad concreta del mundo (una habitación, cosa, etc.), en el caso de que lo escribamos en el formulario de una entidad; o al mundo en su conjunto, si lo escribimos en el panel del mundo. La idea es que el comportamiento de cada entidad se especifique dentro de esa entidad, de modo que las entidades sean unidades autocontenidas que se puedan llevar fácilmente de un mundo a otro. Por ejemplo, si definimos una máquina de coser, querremos que el código que usamos para que cosa esté definido en la entidad «máquina de coser»: de este modo no sólo queda más claro dónde buscar el código de cada cosa, sino que además nos podríamos llevar esa entidad a otra aventura y seguiría cosiendo. El panel de código del mundo, por lo tanto, se utilizará para comportamientos que no estén asociados a una entidad particular, sino al juego en general. 2.1.2. Los métodos El código que escribamos en un formulario siempre tendrá que constar de uno o más métodos. Un método es una porción de código que recibe unos datos de entrada y los procesa de una u otra manera, y, para los que vengan de otros lenguajes, es algo análogo al concepto de función o subrutina. El código de un método consta de una cabecera, que indica qué datos espera el método como entrada y cuáles produce como salida, y un cuerpo escrito entre llaves que contiene las instrucciones ejecutadas por el método. Las cabeceras de los métodos no hace falta escribirlas, las podemos generar directamente con los menús del PUCK. Sólo hará falta escribir, pues, el cuerpo de los métodos (parte delimitada por llaves). Por ejemplo, en el siguiente método: v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s ) { i f ( e q u a l s ( verb , " s a l u d a r " ) ) a C r e a t u r e . w r i t e ( " H o l a . n" ) ; end ( ) ; } La cabecera es v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s ) donde: 1. Mobile aCreature, String verb, String args es la lista de argumentos o pa- rámetros de entrada del método. Cada parámetro corresponde a un dato que el método espera recibir cuando se ejecute. Cuando usemos BeanShell
  • 26. 26 Uso del lenguaje BeanShell para mundos en AGE, normalmente será el AGE quien invoque la mayoría de los métodos y nos proporcione los datos de los parámetros. 2. Cada una de las tres partes separadas por comas en la lista de parámetros (por ejemplo, String verb) es la definición de un parámetro de entrada. Un método puede tener cualquier cantidad de parámetros de entrada, incluyendo no tener ninguno (en cuyo caso no habría nada dentro de los paréntesis). La declaración de un parámetro consta de un tipo de dato y un identificador o nombre. En el ejemplo, String sería el tipo de dato (indicando que ese parámetro es una cadena de texto) y verb sería el nombre. El tipo de dato tiene que ser uno de los que soporta AGE o Java (hay formas de crearlos nuevos, pero no las usaremos); mientras que el nombre es totalmente arbitrario mientras dentro del mismo método nos refiramos al parámetro siempre por el mismo nombre: por ejemplo, podríamos haberle llamado a ese parámetro verbo en lugar de verb, y todo funcionaría igual mientras cambiáramos ese nombre también en el cuerpo del método (if ( equals(verbo,"saludar") )); pero no podríamos hacer un cambio semejante con el tipo de dato. 3. Algunos de los tipos de datos más usados son: int: número entero. boolean: representa algo que puede ser verdadero o falso, tiene dos valores válidos: true o false. double: permite representar números con cifras decimales. char: representa una letra o símbolo. String: cadena de texto. World: mundo de AGE. Entity: cualquier entidad del mundo. Item: cosa del mundo. Mobile: criatura del mundo. Room: habitación del mundo. 4. Al escribir los tipos de datos, es importante respetar las convenciones de mayúsculas y minúsculas que se ven en la lista (BeanShell es sensible a mayúsculas y minúsculas). El motivo de que unos tipos de dato se escriban con minúscula y otros con mayúscula es que los que son con mayúscula corresponden a objetos (y se llaman clases, es decir, Room es un tipo de dato que es una clase y la habitación de Pedro sería un objeto de tipo Room) mientras que los que son con minúscula son tipos de datos que se llaman básicos y corresponden a valores (como el entero −4, el booleano false o el double 3,25) y no a objetos. En AGE usaremos muy pocos tipos básicos (de hecho, sólo los de la lista y uno más que mencionaremos ahora mismo); sin embargo podremos usar bastantes clases (no sólo las de la lista), que iremos viendo. 5. parseCommand es el nombre del método, que junto con los tipos de los parámetros (no sus nombres) es lo que lo identifica y distingue de otros. En general, el nombre puede ser cualquier palabra que cumpla ciertas
  • 27. Primeros pasos con BeanShell 27 reglas (por ejemplo si tiene sólo letras mayúsculas y minúsculas siempre servirá). 6. Lo que viene antes del nombre, en este caso void, es el tipo de retorno del método. Y es que, además de procesar unos parámetros de entrada, un método puede devolver un resultado como salida. El tipo básico void es un tipo básico especial que no tiene ningún valor, y se utiliza en el caso en que un método no devuelve nada. 7. En general, podemos definir métodos con cualquier combinación de nom- bre, parámetros y tipo de retorno. Pero como normalmente vamos a querer que AGE ejecute nuestros métodos, para que así queden integrados en el conjunto de la aventura, necesitaremos ponerles unos nombres (y tipos de parámetros y de retorno, aunque no necesariamente nombres de paráme- tros, que como dijimos son arbitrarios) determinados que son los que el AGE espera encontrar. Sin embargo, no es necesario saber de memoria los nombres y parámetros de los métodos que invoca AGE, ya que el PUCK nos generará automáticamente una plantilla de los mismos desde los me- nús contextuales de los formularios de código. Por ejemplo, si en el PUCK abrimos el área en que se introduce el código del mundo y vamos a su menú contextual con el botón derecho, seleccionando la opción «Insertar código – Método de análisis de la entrada (estándar)» se nos generará au- tomáticamente una plantilla que contendrá la cabecera del método y unos comentarios sobre para qué sirve el método y la función de cada pará- metro. Eso sí, el cuerpo del método que aparece automáticamente estará vacío y por lo tanto no hará nada, tendremos que rellenarlo nosotros para que haga algo. 8. Si generamos esta plantilla, o cualquier otra con el PUCK, veremos tex- to que viene después de dobles barras. El texto que viene en una línea después de una doble barra es un comentario de código y no se ejecuta, es simplemente para que nosotros escribamos explicaciones de qué hace ese código o cosas que queramos recordar. Lo mismo sucede con el texto comprendido entre /* y */, que puede ocupar una o varias líneas. Los comentarios de código pueden ir en cualquier parte del mismo: sea en la cabecera de un método, en su cuerpo, o incluso fuera de cualquier método, ya que AGE los ignora por completo y no los ejecuta. // e s t o e s un c o m e n t a r i o /∗ y e s t o t a m b i é n ∗/ El cuerpo del método del ejemplo anterior es el código entre llaves: { i f ( e q u a l s ( verb , " s a l u d a r " ) ) a C r e a t u r e . w r i t e ( " H o l a . n" ) ; end ( ) ; } Y lo que hace es que, si la cadena (verbo) que nos han pasado como segundo parámetro corresponde a la palabra «saludar» (sin comillas), entonces escribi- mos una línea que dice «Hola.» en la salida asociada a la criatura que viene dada como primer parámetro.
  • 28. 28 Uso del lenguaje BeanShell 2.1.3. Variables y entrada/salida sencilla Ahora que ya sabemos que tenemos que definir métodos y que estructura básica tienen, y tenemos una idea de cómo obtener sus cabeceras con el PUCK, vamos a ver qué tipo de cosas podemos poner en los cuerpos de los métodos para ejecutar código útil. Para ello, por el momento siempre partiremos del método void parseCommand(Mobile aCreature, String verb, String args) cuya cabecera se genera automáticamente en la opción «Insertar código – Método de análisis de la entrada (estándar)» del menú contextual del campo de código de mundo. Ese método lo invoca AGE cuando un jugador introduce una entrada, y los parámetros que recibe son, por orden: el objeto que representa al jugador que ha escrito esa entrada (de momento el único jugador, ya que nos centraremos en aventuras para un solo jugador), el verbo que ha puesto (o primera palabra de la cadena que ha tecleado en la entrada), y el resto de la cadena de entrada. Por ejemplo, si el jugador teclea «comer el plátano de Canarias», entonces el parámetro aCreature corresponderá a ese jugador, el parámetro verb a la cadena «comer», y args a la cadena «el plátano de Canarias». Mostrándole texto al jugador Una de las primeras cosas que podemos hacer es probar a mostrar un texto al jugador cada vez que se ejecute el método (es decir, en el caso de este método particular, cada vez que escribe algo). Esto podríamos hacerlo así: v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s ) { a C r e a t u r e . w r i t e ( " H o l a . n" ) ; } Si ponemos este código en el mundo, cada vez que el jugador escriba algo, AGE le dirá «Hola». La sintaxis aCreature.write("Hola.n") significa que queremos al método write del objeto aCreature, y pasarle como parámetro la cadena "Hola.n". Para ello, tiene que haber definido en la clase a la que pertenece aCreature (o sea, la clase Mobile) un método llamado write que coja una cadena como único parámetro, y efectivamente, este método existe, y lo que hace es escribir algo por la ventana o consola de esa criatura. El punto y coma sirve para terminar la instrucción. Se pueden ejecutar varias instrucciones en secuencia, una después de otra, escribiéndolas una después de otra. No se debe olvidar poner un punto y coma después de cada una: v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s ) { a C r e a t u r e . w r i t e ( " E s t a l í n e a s e e s c r i b e p r i m e r o . n" ) ; a C r e a t u r e . w r i t e ( "Y é s t a s e e s c r i b e " ) ; a C r e a t u r e . w r i t e ( " d e s p u é s . n" ) ; } La secuencia de caracteres n dentro de una cadena significa un salto de línea. Por lo tanto, este código escribirá dos líneas, una que dirá «Esta línea se escribe primero.» y otra que dirá «Y ésta se escribe después.».
  • 29. Primeros pasos con BeanShell 29 La función end() Si probamos a ejecutar nuestra aventura de ejemplo con el código que hemos añadido, veremos que la salida es algo similar a esto: > inventario Esta línea se escribe primero. Y ésta se escribe después. No tienes nada. > asdasf Esta línea se escribe primero. Y ésta se escribe después. No entiendo... Es decir, nuestra aventura está diciéndole escribiéndole al jugador el texto cada vez que escribe algo, pero después está siguiendo el procesado normal que hace AGE (por ejemplo, mostrar el inventario si lo que escribió fue «inventario»). Si en lugar de esto se quiere que el método que hemos definido sustituya al procesado por defecto de AGE, es decir, que cuando un jugador escriba algo se le escriba el texto dado y nada más, podemos utilizar la función end(): v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s ) { a C r e a t u r e . w r i t e ( " E s t a l í n e a s e e s c r i b e p r i m e r o . n" ) ; a C r e a t u r e . w r i t e ( "Y é s t a s e e s c r i b e " ) ; a C r e a t u r e . w r i t e ( " d e s p u é s . n" ) ; end ( ) ; } De esta forma nuestra salida será > inventario Esta línea se escribe primero. Y ésta se escribe después. > asdasf Esta línea se escribe primero. Y ésta se escribe después. Podemos utilizar la función end() para interrumpir el procesado normal del AGE en cualquier momento de la mayoría de los métodos. La plantilla que el PUCK genera de cada método da información explícita sobre si se puede usar o no la función end(). A end() le hemos llamado función, y no método, porque no está asocia- da a un objeto. Un método se invoca sobre un objeto, con la sintaxis obje- to.método(parámetros),1 mientras que una función se invoca sin más, con la sintaxis función(parámetros). Variables y asignaciones En BeanShell, como en otros muchos lenguajes de programación, una varia- ble es un nombre simbólico que se asocia a un determinado valor u objeto en 1 O a veces sobre una clase, con la sintaxis Clase.método(parámetros). Los métodos que se invocan sobre una clase se llaman métodos estáticos
  • 30. 30 Uso del lenguaje BeanShell memoria, que pueden cambiar a lo largo de la ejecución del código. Los pará- metros de los métodos, que vimos con anterioridad, son un tipo particular de variables que almacenan los datos y objetos que se pasan como entradas a un método; pero como programadores también podemos crear otras variables para almacenar todo tipo de información temporal que se utilice en el interior de un método. Una variable tiene tres atributos esenciales: su nombre, su tipo de dato y su valor. El nombre es simplemente una palabra que el programador escoge para referirse a la variable, mientras que el tipo de dato describe qué valores puede contener la variable. Los tipos de datos son los mismos que hemos visto en la sección sobre los parámetros de los métodos, que pueden ser tipos básicos o clases. Un ejemplo de uso de variables podría ser el siguiente: si estamos escribiendo un código para describir todos los objetos que un jugador lleva en su inventario, probablemente usaremos una variable para llevar cuenta de cuántos objetos llevamos descritos (que será de tipo int, pues el número de objetos descritos en cada momento es un número entero) y otra variable donde almacenaremos temporalmente cada objeto al consultarlo en el inventario para describirlo (que será de la clase Item, que representa las cosas en AGE). Para crear una nueva variable, se utiliza una sintaxis como ésta: int index ; donde int es el tipo de datos de la variable que queremos declarar, e index es su nombre. Para asignarle un nuevo valor a una variable ya declarada, lo hacemos de la siguiente manera: index = 0; Con este código estamos haciendo que la variable entera index tome como valor el número entero 0. Es importante tener en cuenta que cada variable sólo puede tomar valores legales según su tipo de datos. Por ejemplo, a una variable entera le podemos dar el valor 0; pero no le podemos dar el valor «Hola» o 3,5, porque éstos no son números enteros. Aquí vemos cómo podemos asignar valores a variables de distintos tipos: int index ; d o u b l e number ; boolean c o n d i t i o n ; char l e t t e r ; S t r i n g name ; Room aRoom ; Item anItem ; Mobile aCreature ; i n d e x = −4; number = 7 . 2 3 ; c o n d i t i o n = t r u e ; // o f a l s e l e t t e r = ’ a ’ ; // l o s v a l o r e s de t i p o c a r á c t e r s e e s c r i b e n // e n t r e c o m i l l a s s i m p l e s name = " P a b l o P i c a s s o " ; // l o s v a l o r e s de t i p o c a d e n a ( S t r i n g ) // s e e s c r i b e n e n t r e c o m i l l a s d o b l e s aRoom = room ( " S a l a d e l t r o n o " ) ; // room ( ) e s una f u n c i ó n a l a que // l e pasamos una c a d e n a y n o s d e v u e l v e l a
  • 31. Primeros pasos con BeanShell 31 // h a b i t a c i ó n que t i e n e e s a c a d e n a como nombre ú n i c o a n I t e m = i t e m ( " B o l í g r a f o " ) ; // i t e m ( ) e s a n á l o g o a room ( ) , // p e r o con una c o s a a C r e a t u r e = m o b i l e ( " Juan " ) ; // m o b i l e ( ) e s a n á l o g o a room ( ) , // p e r o con una c r i a t u r a Este proceso se puede abreviar asignando un valor inicial a las variables a la vez que las creamos, de la siguiente manera: i n t i n d e x = −4; d o u b l e number = 7 . 2 3 ; boolean c o n d i t i o n = true ; char l e t t e r = ’ a ’ ; S t r i n g name = " P a b l o P i c a s s o " ; Room aRoom = room ( " S a l a d e l t r o n o " ) ; Item anItem = item ( " B o l í g r a f o " ) ; M o b i l e a C r e a t u r e = m o b i l e ( " Juan " ) ; A las variables también se les puede asignar el valor de otra variable, o el valor que devuelve una expresión (que puede contener operaciones o llamadas a métodos o funciones): int index = 7; i n t i n d e x 2 = i n d e x ; // c o p i a m o s e l v a l o r de i n d e x a i n d e x 2 , // a h o r a i n d e x 2 v a l e 7 i n t i n d e x 3 = i n d e x 1 + i n d e x 2 ; // l a e x p r e s i ó n i n d e x 1 + i n d e x 2 // d e v u e l v e l a suma de i n d e x 1 e i n d e x 2 , a h o r a i n d e x 3 v a l e 14 i n d e x 3 = i n d e x 3 + 1 ; // i n c r e m e n t a m o s i n d e x 3 en 1 I t e m arma = i t e m ( " Espada " ) ; // ob t e n e mo s e l o b j e t o de nombre // ú n i c o " Espada " y l o almacenamos en l a v a r i a b l e arma i n t pesoArma = arma . g e t W e i g h t ( ) ; // g e t W e i g h t ( ) e s un método de l a // c l a s e I t e m que n o s d e v u e l v e e l p e s o de una c o s a . Aquí ponemos // e l p e s o de n u e s t r a e s p a d a en l a v a r i a b l e pesoArma . Nótese // que podemos h a c e r e s t o p o r q u e e l t i p o de r e t o r n o del // método g e t W e i g h t ( ) e s i n t , y e l t i p o de l a variable // pesoArma t a m b i é n e s i n t . En g e n e r a l no podemos asignar // a una v a r i a b l e un v a l o r que no s e a de s u t i p o i n t d o b l e P e s o A r m a = arma . g e t W e i g h t ( ) ∗ 2 ; // e l ∗ e s e l o p e r a d o r // de m u l t i p l i c a c i ó n . Como vemos , s e pueden c o m b i n a r llamadas // a métodos con o p e r a c i o n e s p a r a f o r m a r una e x p r e s i ó n que // d e v u e l v e un v a l o r , v a l o r que s e pu e de d e s p u é s m e t e r en una v a r i a b l e arma = 7 ; // e s t o f a l l a r í a porque intentamos a s i g n a r a l a // v a r i a b l e arma , de t i p o Item , e l v a l o r 7 , de t i p o int . //No c o i n c i d e n l o s t i p o s , a s í que l a a s i g n a c i ó n no s e p ue de // l l e v a r a cabo
  • 32. 32 Uso del lenguaje BeanShell Operaciones con los tipos básicos En la sección anterior hemos visto algunos ejemplos de cómo se hacen opera- ciones, como por ejemplo una suma. Veamos aquí una lista algo más exhaustiva de operaciones útiles. Con int: int a = 7; int b = 4; int c; c = a + b; // suma a y b ( c v a l d r í a 1 1 ) c = a − b; // r e s t a a menos b ( c v a l d r í a 3 ) c = a ∗ b; // m u l t i p l i c a a p o r b ( c v a l d r í a 2 8 ) c = a / b; // d i v i s i ó n e n t e r a de a e n t r e b ( c v a l d r í a 1 ) c = a %b; // r e s t o de l a d i v i s i ó n e n t e r a de a e n t r e b ( c v a l d r í a 3 ) . a++; // i n c r e m e n t a l a v a r i a b l e a ( e s e q u i v a l e n t e a p o n e r a = a + 1 ) a−−; // d e c r e m e n t a l a v a r i a b l e a ( e s como p o n e r a = a − 1 ) a ∗= 3 ; // a b r e v i a t u r a de a = a ∗ 3 . E s t o s e p ue d e h a c e r análogamente // con t o d o s l o s o p e r a d o r e s de l o s t i p o s b á s i c o s que aparecen // en e s t a s e c c i ó n . Con double: d o u b l e a = 7 . 0 ; // n ó t e s e e l . 0 p a r a i n d i c a r que e l v a l o r s e // c o n s i d e r a un d o u b l e y no un i n t , aunque m a t e m á t i c a m e n t e // s e a e l mismo v a l o r double b = 4 . 0 ; double c ; c = a + b ; // suma a y b ( c v a l d r í a 1 1 . 0 ) c = a − b ; // r e s t a a menos b ( c v a l d r í a 3 . 0 ) c = a ∗ b ; // m u l t i p l i c a a p o r b ( c v a l d r í a 2 8 . 0 ) c = a / b ; // d i v i s i ó n con d e c i m a l e s de a e n t r e b ( c v a l d r í a 1 . 7 5 ) Con cadenas: S t r i n g a = " Juan " ; S t r i n g b = " Pepe " ; S t r i n g c = a + b ; // l a " suma " de c a d e n a s e s s u // c o n c a t e n a c i ó n : l a c a d e n a " JuanPepe " int a = 7; double b = 3 . 0 ; S t r i n g m e n s a j e = " La v a r i a b l e a v a l e " + a + " y l a v a r i a b l e b vale " + b; // l a s c a d e n a s t a m b i é n s e pueden c o n c a t e n a r con o t r o s tipos de d a t o s , // en c u y o c a s o e s o s v a l o r e s s e c o n v i e r t e n a c a d e n a s . En este // c a s o m e n s a j e q u e d a r í a como " La v a r i a b l e a v a l e 7 y la variable b // v a l e 3 . 0 " Con booleanos: boolean s i = true ; b o o l e a n no = f a l s e ; boolean r e s u l t a d o ;
  • 33. Primeros pasos con BeanShell 33 r e s u l t a d o = ! s i ; // l a ! e s e l o p e r a d o r n o t ( n e g a c i ó n ) . // A p l i c a d o a t r u e , d e v u e l v e f a l s e , y a p l i c a d o a f a l s e , // d e v u e l v e t r u e . r e s u l t a d o = s i | | no ; // o p e r a d o r o r l ó g i c o . // D e v u e l v e t r u e s i a l menos uno de l o s d o s o p e r a n d o s // e s t r u e ( en e s t e c a s o d e v o l v e r í a t r u e ) . r e s u l t a d o = s i && no ; // o p e r a d o r and l ó g i c o . // D e v u e l v e t r u e s ó l o cuando l o s d o s o p e r a n d o s s o n // t r u e ( en e s t e c a s o d e v o l v e r í a f a l s e ) . Los operadores se pueden combinar en expresiones complejas, utilizando pa- réntesis si es necesario para definir el orden: i n t d = a + b + c ; // suma de a , b y c d = ( a + b ) ∗ c ; // sumar a y b , y m u l t i p l i c a r e l r e s u l t a d o p o r c S t r i n g j u a n e s = a + a + a ; // " J u a n J u a n J u a n " j u a n e s += j u a n e s ; // " J u a n J u a n J u a n J u a n J u a n J u a n " b o o l e a n c o m p l e j o = ( s i && s i ) | | ( no | | no ) ; // e s t o da t r u e 2.1.4. La estructura condicional (if) Hasta ahora, hemos visto cómo crear un método, escribir cosas en la pan- talla o ventana del jugador y crear o actualizar variables. Estas instrucciones se pueden combinar en secuencias para que se ejecuten unas después de otras; pero con lo que de momento hemos visto, nuestro método siempre hará exac- tamente lo mismo, una secuencia de operaciones predeterminadas. Esto limita mucho el conjunto de cosas que podemos hacer. Para crear métodos más intere- santes, necesitamos de alguna forma poder hacer que se comporten de manera diferente según las circunstancias: por ejemplo, que el método parseCommand que estamos definiendo actúe de manera distinta según el verbo que ha escrito el jugador, o según la habitación en la que está, si ha realizado o no con an- terioridad una determinada acción, o cualquier otra circunstancia que se nos ocurra. Para conseguir estos comportamientos diferentes según las circunstancias, podemos utilizar la estructura condicional, llamada if. La estructura condicional nos permite definir un código que sólo se ejecuta si se cumple una determina- da condición (por ejemplo, que el jugador esté en la habitación «cocina»), y, opcionalmente, otro código que sólo se ejecuta si no se cumple la condición: Mobile jugador = aCreature ; i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) ) j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a . n" ) ; else j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en o t r a p a r t e que no e s l a c o c i n a . n" ) ; En general, la sintaxis de la instrucción if para ejecutar un código si y sólo si se cumple una determinada condición es la siguiente: if ( condición ) cuerpo Donde el código de cuerpo sólo se ejecutará en el caso de que condición sea cierta. En concreto, condición tiene que ser siempre una expresión que devuelva un valor de tipo boolean (true o false). El código de cuerpo se ejecutará si el valor de condición es true, y no se ejecutará si dicho valor es false.
  • 34. 34 Uso del lenguaje BeanShell En el caso de que el cuerpo del if esté formado por varias instrucciones, se deben delimitar dichas instrucciones con llaves, como si fueran el cuerpo de un método: i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) ) { j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a . n" ) ; j u g a d o r . w r i t e ( "Te dan g a n a s de p o n e r t e a c o c i n a r a l g o . n" ) ; } Si el cuerpo del if está formado por una única instrucción, se puede poner la instrucción sin más, sin llaves: i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) ) j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a . n" ) ; O bien ponerla con llaves como antes, que en este caso es equivalente: i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) ) { j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a . n" ) ; } La sintaxis de la estructura if para ejecutar un código si se cumple una condición y otro distinto si no se cumple es la siguiente: if ( condición ) cuerpo1 else cuerpo2 De nuevo, cuerpo1 y cuerpo2 tienen que ir necesariamente entre llaves si tienen más de una instrucción, y pueden ir sin llaves si tienen sólo una. i f ( e q u a l s ( room ( " C o c i n a " ) , j u g a d o r . getRoom ( ) ) ) { j u g a d o r . w r i t e ( "En e s t o s momentos e s t á s en l a c o c i n a . n" ) ; j u g a d o r . w r i t e ( "Te dan g a n a s de p o n e r t e a c o c i n a r a l g o . n" ) ; } else j u g a d o r . w r i t e ( "No e s t á s en l a c o c i n a . n" ) ; Una estructura «if–else» se puede combinar con otras estructuras «if–else» para dar una estructura «if–else if–else if...–else», como ésta: i f ( e q u a l s ( v e r b , " comer " ) ) j u g a d o r . w r i t e ( " Has p u e s t o e l v e r b o comer . n" ) ; else i f ( equals ( verb , " beber " ) ) j u g a d o r . w r i t e ( " Has p u e s t o e l v e r b o b e b e r . n" ) ; else i f ( equals ( verb , " dormir " ) ) j u g a d o r . w r i t e ( " Has p u e s t o e l v e r b o d o r m i r . n" ) ; else j u g a d o r . w r i t e ( "No e n t i e n d o e l v e r b o que h a s p u e s t o . n" ) ; Este código escribe una cosa u otra en la consola del jugador según el valor del parámetro verb del método. Comparaciones Para decidir entre una rama u otra de una estructura condicional, necesita- mos que nuestro código utilice alguna expresión o variable de tipo boolean, de modo que ejecute la rama del if si esta expresión tiene un valor verdadero, y la rama del else (o nada) si su valor es falso.
  • 35. Primeros pasos con BeanShell 35 ¿Cómo obtenemos expresiones de tipo boolean que sean relevantes para de- finir nuestros métodos if? Existen muchas maneras, dependiendo de lo que uno quiera hacer; pero una de las más básicas y comunes son las comparaciones. Muchas veces queremos ejecutar un código si un valor es igual a otro (por ejem- plo, si el valor de una variable es igual a un valor dado). Esto se consigue con la función de comparación de igualdad equals.2 La comparación de igualdad de AGE es una función equals al que se le pasan dos parámetros que pueden ser de cualquier tipo (tipos básicos u objetos). La función equals devuelve true si los dos parámetros que se le han pasado tienen el mismo valor, y false si son distintos. Así, por ejemplo, podríamos hacer lo siguiente: e q u a l s ( 3 , 4 ) ; // d e v u e l v e f a l s e e q u a l s ( 3 , 3 ) ; // d e v u e l v e t r u e e q u a l s ( 2 + 2 , 4 ) ; // d e v u e l v e t r u e e q u a l s ( 2 + 2 , 5 ) ; // d e v u e l v e f a l s e e q u a l s ( " F u l a n i t o " , " M e n g a n i t o " ) ; // d e v u e l v e f a l s e String f = " Fulanito " ; e q u a l s ( " F u l a n i t o " , f ) ; // d e v u e l v e t r u e S t r i n g g = " Fula " ; String h = " nito " ; e q u a l s ( f , g ) ; // d e v u e l v e f a l s e e q u a l s ( f , h ) ; // d e v u e l v e f a l s e e q u a l s ( f , g+h ) ; // d e v u e l v e t r u e e q u a l s ( room ( " C o c i n a " ) , room ( " C o c i n a " ) ) ; // d e v u e l v e t r u e e q u a l s ( room ( " C o c i n a " ) , room ( " Baño " ) ) ; // d e v u e l v e f a l s e ( s a l v o que no e x i s t a n h a b i t a c i o n e s l l a m a d a s C o c i n a n i Baño , en c u y o c a s o s e c o n s i d e r a n i g u a l e s p o r q u e n i n g u n a de l a s d o s e x i s t e ) Podemos ver un uso práctico de una comparación de igualdad en conjun- ción con una estructura condicional si, en el método parseCommand visto con anterioridad, queremos hacer que se responda de una manera determinada sólo cuando el jugador escribe un determinado verbo. Por ejemplo: v o i d parseCommand ( M o b i l e a C r e a t u r e , S t r i n g v e r b , S t r i n g a r g s ) { i f ( e q u a l s ( v e r b , " comer " ) ) { a C r e a t u r e . w r i t e ( "No p u e d e s comer a h o r a , que e s t á s a r é g i m e n . n" ); end ( ) ; } } Con esto conseguimos que cuando el jugador use el verbo comer, se le diga que está a régimen, sin cambiar el comportamiento de los otros verbos: > inventario Tienes una manzana. > comer la manzana No puedes comer ahora, que estás a régimen. 2 Nota para programadores: BeanShell tiene otras comparaciones de igualdad por defecto, que son el método equals de la clase Object y el operador ==. La función equals que se cubre aquí es una función de más alto nivel creada a propósito para simplificar las comparaciones en AGE, cubriendo los casos de uso más comunes en las aventuras. Los programadores que tengan conocimientos de Java o de BeanShell pueden utilizar en su lugar las comparaciones tradicionales con el método equals de Object y con ==, que por supuesto funcionan en AGE como en Java.
  • 36. 36 Uso del lenguaje BeanShell Nótese que el end() está dentro del cuerpo del if, con lo cual sólo se impide que AGE ejecute sus comportamientos estándar si realmente se usa el verbo comer. Si hubiésemos puesto el end() fuera del cuerpo del if, haríamos que dejara de funcionar el comando «inventario» (y cualquier otro) porque el end() se ejecutaría siempre e impediría que AGE ejecutase sus comportamientos por defecto. Si no hubiésemos puesto un end() en absoluto, ni siquiera dentro del if, entonces al usar el verbo «comer» se imprimiría nuestro mensaje pero después se seguiría procesando la entrada como si tal cosa, cosa que provocaría efectos no deseados: > comer la manzana No puedes comer ahora, que estás a régimen. ¿Cómo? ¿Comer? En este caso, imprimimos el mensaje pero luego AGE procesa el comando, y como por defecto no lo entiende (no está definido por defecto en AGE qué pasa al comer algo), da un mensaje de error. Hay que tener cuidado, pues, de usar los end() en los momentos en que se necesitan. Si en lugar de comprobar si dos cosas son iguales queremos comprobar si son distintas, podemos utilizar el operador ! visto antes, que niega un valor booleano. Así, equals(verb,"comer") devuelve true si y sólo si el parámetro verb tiene como valor «comer»; mientras que !equals(verb,"comer") devuelve true sólo si el valor del parámetro no es «comer». En el caso de trabajar con números (sean int o double), a menudo nos intere- sará hacer comparaciones de superioridad y de inferioridad, en lugar de las de igualdad. Es decir, querremos saber si un número es mayor o menor que otro. Esto se hace con los operadores <, >, <= y >=: boolean b ; b = ( 4 > 3 ) ; // d e v u e l v e t r u e b = ( 4 >= 3 ) ; // d e v u e l v e f a l s e b = ( 4 >= 4 ) ; // d e v u e l v e t r u e b = ( 4 . 2 > 3 . 5 ) ; // d e v u e l v e t r u e b = ( 4 < 3 ) ; // d e v u e l v e t r u e b = ( 3 < 4 ) ; // d e v u e l v e t r u e ; i f ( x >= 0 ) a C r e a t u r e . w r i t e ( " E q u i s e s mayor que c e r o . n" ) ; // p a r a e s t o t e n d r e m o s que h a b e r d e c l a r a d o a n t e s l a v a r i a b l e x 2.1.5. Los bucles La estructura condicional (if–else) que hemos visto es una de las principales estructuras de control, es decir, maneras de gestionar qué camino va siguiendo un programa en BeanShell para ejecutar sus instrucciones. Las otras estructuras de control importantes que necesitaremos para gestionar el flujo de los programas son los bucles. Como hemos visto, una estructura condicional nos permite escoger entre un código a ejecutar y otro según si se da o no una determinada condición. Este código que se ejecuta lo hace únicamente una vez (salvo que estemos llamando al if varias veces desde código externo a él, claro). Los bucles nos permiten ejecutar un bloque de código varias veces, repitién- dose mientras una condición determinada se cumpla. El código del cuerpo del