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:
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.
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(); } }
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).
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):
parseCommand
.parseCommand
funcionaría también para “toma el plátano”. 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.parseCommand
ejecutados en el paso anterior no se llamó a end()
, hay dos posibilidades:
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.