Herramientas de usuario

Herramientas del sitio


metodos_de_analisis_de_la_entrada_parsecommand

Los métodos de análisis de la entrada

En el funcionamiento típico de los juegos basados en texto, los jugadores introducen lo que quieren que sus personajes hagan en forma de órdenes dadas como cadenas de texto. El juego lee entonces estas cadenas de texto y, si consigue interpretar su significado, ejecuta las acciones desencadenadas por la orden del jugador.

Los métodos de análisis de la entrada (o métodos parseCommand) son, probablemente, los métodos redefinibles más importantes del Aetheria Game Engine, ya que permiten al creador de juegos inyectar código para cambiar la manera en que se analiza la entrada, y por lo tanto también las acciones que ésta desencadena.

Algunas de las cosas más comunes que se pueden hacer con los métodos parseCommand son:

  • Definir nuevos verbos y órdenes que no estén definidos por defecto en el AGE.
  • Cambiar el comportamiento por defecto de las órdenes que sí existen en el AGE, haciendo que en nuestro juego hagan otra cosa en lugar de (o aparte de) ejecutar el comportamiento por defecto.
  • Definir o cambiar el comportamiento de órdenes situacionalmente; es decir, hacer que una orden tenga normalmente el comportamiento por defecto, pero actúe de forma distinta en determinadas situaciones (cuando se está en una habitación dada, se ejecuta sobre un objeto determinado, etc.)

Aparte de estos usos, que son los más comunes, la versatilidad de los métodos parseCommand hace que realmente sean pocas las cosas que no se pueden hacer con ellos. Al dejarnos inyectar código que se ejecuta durante el proceso de análisis de la entrada, un programador avanzado puede llegar a cambiar por completo todo el funcionamiento de un juego en AGE, sustituyendo todos los comportamientos por defecto por código propio.

Ejemplo de uso

Como es habitual en los sistemas de creación de juegos basados en texto, Aetheria Game Engine es capaz de interpretar y procesar por defecto las órdenes más comunes. Por ejemplo, si un jugador está en una habitación que contiene un plátano y teclea “cojo el plátano”, el AGE se encargará de hacer que la sabrosa fruta pase a las pertenencias del jugador, mostrándole además el mensaje de texto correspondiente. Esto es porque la acción “coger” es algo común a la mayoría de los juegos de texto: lo normal es que si una cosa no pesa demasiado, y no está fija en el sitio (como lo estaría un adoquín del suelo), se pueda coger.

Muchas de las acciones que se llevan a cabo en un juego de texto típico son acciones estándar comunes a todos los juegos, como la de coger el plátano. Sin embargo, si queremos implementar un buen juego, lo normal es que en algún momento necesitemos crear acciones personalizadas, que implementen comportamientos específicos de nuestro juego. Por ejemplo, podemos querer que el personaje se pueda comer el plátano, saciando su hambre y quedándose con una piel de plátano utilizable para hacer resbalar a algún malvado. Como esto no es un comportamiento genérico que venga en el sistema por defecto, lo tendremos que implementar nosotros en el objeto plátano, lo cual se puede hacer mediante un método de análisis de la entrada:

void parseCommand( Mobile aCreature , String verb , String args )
{
    if ( equals(verb,"comer") )
    {
        aCreature.writeAction("Te comes el plátano. ¡Ñam, ñam! ¡Qué rico!\n");
        aCreature.removeItem(item("plátano"));
        aCreature.addItem(item("piel de plátano"));
        end();   
    }
}

Tipos de métodos de análisis de la entrada

Aquí se muestran los diferentes métodos de análisis de la entrada que se pueden redefinir, así como el orden en que AGE los ejecuta. Nótese que esta tabla parece muy complicada; pero no hay ninguna necesidad de saberla en la práctica, se muestra sólo como referencia de consulta para usuarios avanzados. En realidad, muchos de los métodos no son necesarios salvo para usos muy avanzados y específicos. En concreto, los métodos que contienen la subcadena OnContents sólo hacen falta para usos avanzados de contenedores, que les gusta poner a algunos autores pero no son para nada necesarios en una aventura. Muchos de los métodos restantes son alternativos unos a otros, de modo que unos autores pueden preferir por comodidad usar unos y otros autores usar otros: por ejemplo, un método parseCommandGeneric hace todo lo que pueden hacer parseCommandObj1, parseCommandObj2, parseCommandTwoObjects y parseCommand; pero unos autores pueden preferir utilizar un sólo método más complejo para todas las situaciones, y otros usar varios métodos más sencillos y adaptados a cada situación específica. También cabe destacar que no es necesario para nada saber los nombres, parámetros y función de estos métodos, ya que los menús de PUCK nos permiten encontrar el método que queremos y generar su declaración y explicación de parámetros automáticamente (en la columna derecha se muestra el menú del PUCK que conduce a cada método).

Orden de ejecución Objeto donde se define Signatura del método Nomenclatura en menús de PUCK
1 Player String parseCommand( String verb , String args ) Método de análisis de la entrada (estándar) → Introducida por este jugador
2 Mobile/Item void parseCommandOnContentsObj1 ( Mobile aCreature , String verb , String args1 , String args2 , Vector path1 , Vector path2 , Entity obj2 ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a ésta y otra cosa, en ese orden
2 Mobile/Item void parseCommandOnContentsObj2 ( Mobile aCreature , String verb , String args1 , String args2 , Vector path1 , Vector path2 , Entity obj1 ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a otra cosa y ésta, en ese orden
3 Mobile/Item void parseCommandOnContentsTwoObjects ( Mobile aCreature , String verb , String args1 , String args2 , Vector path1 , Vector path2 , Entity otherEnt ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a ésta y otra cosa, en cualquier orden
3,6* Mobile/Item void parseCommandOnContentsGeneric ( Mobile aCreature , String verb , String args1 , String args2 , Vector path1 , Vector path2 , Entity obj1 , Entity obj2 , boolean goesFirst ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a ésta y, opcionalmente, otra cosa
4 Mobile/Item void parseCommandObj1 ( Mobile aCreature , String verb , String args1 , String args2 , Entity obj2 ) Método de análisis de la entrada (estándar) → Referente a ésta y otra cosa, en ese orden
4 Mobile/Item void parseCommandObj2 ( Mobile aCreature , String verb , String args1 , String args2 , Entity obj1 ) Método de análisis de la entrada (estándar) → Referente a otra cosa y ésta, en ese orden
5 Mobile/Item void parseCommandTwoObjects ( Mobile aCreature , String verb , String args1 , String args2 , Entity otherEnt ) Método de análisis de la entrada (estándar) → Referente a ésta y otra cosa, en cualquier orden
5,7* Mobile/Item void parseCommandGeneric ( Mobile aCreature , String verb , String args1 , String args2 , Entity obj1 , Entity obj2 , boolean goesFirst ) Método de análisis de la entrada (estándar) → Referente a ésta y, opcionalmente, otra cosa
6 Mobile/Item void parseCommandOnContents ( Mobile aCreature , String verb , String args , Vector path ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a esta cosa
7 Mobile/Item void parseCommand ( Mobile aCreature , String verb , String args ) Método de análisis de la entrada (estándar) → Referente a esta cosa
8 Room void parseCommand ( Player aPlayer , String verb , String args ) Método de análisis de la entrada
9 World void parseCommandOnContentsTwoObjects ( Mobile aCreature , String verb , String args1 , String args2 , Vector path1 , Vector path2 , Entity obj1 , Entity obj2 ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a dos cosas
9,11* World void parseCommandOnContentsGeneric ( Mobile aCreature , String verb , String args1 , String args2 , Vector path1 , Vector path2 , Entity obj1 , Entity obj2 ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a una o dos cosas
10 World void parseCommandTwoObjects ( Mobile aCreature , String verb , String args1 , String args2 , Entity obj1 , Entity obj2 ) Método de análisis de la entrada (estándar) → Referente a dos cosas
10,12* World void parseCommandGeneric ( Mobile aCreature , String verb , String args1 , String args2 , Entity obj1 , Entity obj2 ) Método de análisis de la entrada (estándar) → Referente a una o dos cosas
11 World void parseCommandOnContents ( Mobile aCreature , String verb , String args , Vector path , Entity target ) Método de análisis de la entrada (para contenedores y objetos contenidos) → Referente a una cosa
12 World void parseCommand ( Mobile aCreature , String verb , String args , Entity target ) Método de análisis de la entrada (estándar) → Referente a una cosa
13 World void parseCommand ( Mobile aCreature , String verb , String args ) Método de análisis de la entrada (estándar) → Para cualquier entrada

* Los métodos de tipo “generic” se muestran con dos órdenes de ejecución porque pueden ejecutarse tanto para procesar comandos que se refieren a dos entidades del mundo como para los que se refieren a uno solo. Para el caso de dos entidades, se ejecutan junto a los métodos análogos que procesan comandos referidos a dos entidades (en el primer orden que aparece en la tabla). Para el caso de una entidad, se ejecutan junto a los demás métodos para una entidad (en el segundo orden).

El proceso de análisis de AGE

Para ahorrar trabajo al creador de juegos y que no tenga que encargarse de interpretar las frases que introduce el jugador, sino sólo de definir qué cosas puede hacer su juego; el AGE lleva a cabo por sí solo un análisis sintáctico de la entrada, pasándole al creador de aventuras (a través de los métodos parseCommand) una entrada ya preprocesada. Por ejemplo, si el jugador teclease “coge el plátano y cómelo”, AGE rompería el comando en sus dos partes y se encargaría de los pronombres y los tiempos verbales, traduciéndolo como “coger el plátano”, por un lado, y “comer el plátano”, por otro. De este modo, el método parseCommand que vimos en el ejemplo anterior funcionará para “coge el plátano y cómelo”; aunque el verbo no esté en infinitivo como aparece en el código, y aunque el jugador haya tecleado “cómelo” en lugar de poner explícitamente “comer el plátano”.

NOTA: Si en algún caso se hace necesario analizar toda la entrada a mano, sin que AGE lleve a cabo este preprocesado, también es posible; pero esto debe hacerse mediante el método preprocessCommand (véase preprocesado de la entrada) en lugar de parseCommand. Los métodos parseCommand siempre nos dan la entrada preprocesada.

Más en detalle, los pasos del procesado de textos que realiza AGE son los siguientes (no debería ser necesario saber esto salvo para usos muy avanzados):

  1. Si la orden es compuesta, romperla en órdenes simples: así, “coge el plátano y cómelo” se romperá en las dos órdenes “coge el plátano” y “cómelo”. Cada una de ellas se tratará como una orden independiente de cara a todos los métodos parseCommand.
  2. Sustituir los pronombres: cada uno de los pronombres enclíticos se sustituye por el nombre que referencia, con los siguientes criterios:
    1. Para los pronombres “lo” y “la”, se supone que el nombre al que hace referencia el pronombre es el último nombre referenciado por una orden que coincide en género con ese pronombre. Así, el “lo” de “cómelo” se sustituiría por “plátano”, dando lugar a “cóme plátano” (sic). Nótese que la sustitución de pronombres funciona también entre distintas órdenes, es decir, si el jugador primero teclea “coge el plátano”, y más tarde en una línea separada teclea “cómelo”, el pronombre será sustituido igualmente.
    2. Para el pronombre “te”, se supone que el nombre al que hace referencia el pronombre es el primer nombre de referencia del jugador. Así, si por ejemplo el jugador tiene como nombre de referencia Manolo y escribe “mírate”, el resultado será “míra Manolo”, que por defecto en AGE mostrará la descripción de Manolo (pues el jugador funciona como cualquier otra criatura, pudiéndose referir a él las órdenes mediante sus nombres de referencia).
    3. Nótese que el tratamiento del pronombre “te” lo sustituye siempre, incluso en aquéllos casos que se dan en castellano donde el pronombre sólo tiene un valor enfático y no personal. Un ejemplo podría ser “cómete el plátano”: en esa oración, el “te” no significa que el jugador quiera comerse a sí mismo; pero AGE lo sustituirá de igual modo (dando lugar a un “cóme Manolo el plátano”) y será responsabilidad del programador de la aventura tratar ese caso (véase tratamiento de te enfático o pronombre en la entrada para más detalles).
  3. Corregir automáticamente (sólo desde versión 1.0.2): desde la versión 1.0.2 de AGE, si la primera palabra de la orden es algo que se parece mucho a un verbo conocido pero no lo es (por ejemplo, “cgoer”), se cambia por dicho verbo. A partir de la versión 1.0.3, las siguientes palabras también se corrigen si se parecen mucho a un nombre de referencia de un objeto del mundo pero no lo son (por ejemplo, “trajje” por “traje”). Estas funcionalidades se pueden desactivar poniendo la propiedad booleana “noVerbSpellChecking” del jugador a true.
  4. Sustituir las formas verbales por infinitivos: las formas que aparezcan en imperativo o segunda persona son cambiadas por infinitivos, para evitar al programador de juegos el tener que reconocer distintas formas. Así, las órdenes del ejemplo quedarían cambiadas por “coger el plátano” y “comer plátano”.
  5. Sustituir alias: hay algunos verbos que están definidos como sinónimos de otros, para que el programador de aventuras no tenga que tratar individualmente con cada sinónimo. Por ejemplo, “subir” se sustituye por “ir arriba”, y “tomar” se sustituye por “coger”, de modo que el código definido antes para el parseCommand funcionaría también para “toma el plátano”.
  6. Detectar a qué objetos se refiere la orden: la palabra “plátano” no es un sustantivo cualquiera, es un sustantivo que se refiere a una entidad del mundo (siempre que la hayamos puesto como nombre de referencia del plátano, claro). El AGE detecta nombres de referencia en las órdenes y toma nota de a qué entidad hacen referencia.
  7. Ejecutar los parseCommand: se ejecutan los diferentes métodos parseCommand, en el orden que se muestra en la tabla de más arriba. Los parseCommand en concreto que se ejecuten dependerán de las entidades a las que haga referencia la orden: por ejemplo, como “comer plátano” se refiere a una entidad (el plátano), se ejecutará el método parseCommand ( Mobile aCreature, String verb , String args ) de la entidad plátano; pero no se ejecutarán los métodos para órdenes que se refieren a dos entidades (como parseCommandTwoObjects) ya que en la orden no aparecen dos entidades.
  8. Llevar a cabo el comportamiento por defecto, si es posible: si en los parseCommand ejecutados en el paso anterior no se llamó a end(), hay dos posibilidades:
    1. Que la frase empiece por un verbo: en cuyo caso, si hay un comportamiento por defecto para ese verbo (como sucede con “coger”) se ejecuta; mientras que si no lo hay (como en “comer”) se muestra un mensaje para indicar al jugador que la aventura no entiende lo que quiere hacer.
    2. Que la frase no empice por un verbo: en este caso, se repite todo el procesado de la entrada suponiendo que la frase va precedida del último verbo que se ha utilizado; esto es el llamado modo “second chance”. Esto puede servir para interpretar algunos comandos donde se omite el verbo: por ejemplo, si el jugador teclea “comer el plátano” y después sigue con “ahora la manzana”, refiriéndose a que quiere comer la manzana. Si después del modo “second chance” se llega al punto 7.1; es señal de que la frase introducida no era inteligible en absoluto y se muestra el mensaje de que no se ha entendido.

Como programadores de aventuras, lo que nos interesa saber es que en el parseCommand, el AGE siempre nos va a dar órdenes simples (con un solo verbo), con el verbo en infinitivo, y con una serie de sinónimos sustituidos por verbos estándar. Verbos estándar son (lista incompleta) coger, dejar, mirar, ir, poner, decir, vestir, desvestir, atacar, bloquear, esquivar. Algunos verbos no estándar típicos son examinar (se convierte en mirar), tomar (se convierte en coger), quitar (en coger), sacar (en coger), entrar (se convierte en ir dentro), etc.

metodos_de_analisis_de_la_entrada_parsecommand.txt · Última modificación: 2011/12/13 00:43 por al-khwarizmi