Está en la página 1de 35

Tutorial

CreacindeMapas paraeljuegoplman

Actualizado 30deenerode2010

-1-

ndice de contenido
1. Cmo crear un mapa en 6 pasos......................................................................................................3 2. Detalles a la hora de dibujar tu mapa..............................................................................................4 3.Aadiendo vida a los mapas.............................................................................................................6 3.1.Conociendo el formato de archivo de cdigo de Prolog...........................................................6 3.2. Modificando el cdigo del mapa.............................................................................................9 4.Utilizando comportamientos predefinidos......................................................................................11 5.Definiendo comportamientos propios para entidades y objetos.....................................................24 5.1. Sensores y otras yerbas..........................................................................................................25 5.2. Marchando una de memoria..................................................................................................27 5.3. Entidades en tiempo real, Al vuelo!.....................................................................................30 6. Otros predicados interesantes de Pl-man.......................................................................................32

-2-

1. Cmo crear un mapa en 6 pasos


Sigue estos pasos para crear tu propio mapa del juego pl-man. 1. Elige un editor de textos con el que crear el mapa. Te pueden valer el gedit o el joe, o cualquier editor de textos que te permita guardar en formato UTF-8 en Linux. Si tienes algn editor que te permita ver los espacios, tabuladores y dems caracteres no imprimibles, ese ir mejor. Esto lo hace el JCreator, por ejemplo, y creo que code::blocks tambin lo hace. 2. Abre el editor y dibuja un mapa rectangular. El mapa tiene que ser perfectamente rectangular. No puede haber lneas que tengan ms caracteres que otras, porque el conversor te dar error. Ten cuidado con aadir espacios o tabuladores, ya que el conversor tiene en cuenta esos caracteres. Ten cuidado tambin con poner intros al final del archivo, ya que no se ven y tambin cuentan como lneas. Puedes aprender ms sobre el dibujado del mapa consultando la seccin Detalles a la hora de dibujar tu mapa. 3. Guarda tu mapa en formato de texto: UTF-8 en Linux. Para entendernos, un archivo con extensin txt. Supongamos que lo guardas con el original nombre mapa.txt :) 4. Convierte tu mapa en un archivo de cdigo Prolog usando el conversor. Para hacer esto, brete un terminal de lnea de comandos (Alt+F2/gnome-terminal en Linux/gnome o Aplicaciones->Accesorios->Terminal). En el terminal, desplzate hasta el directorio donde debes tener el conversor (txt2plmap y txt2plmap.cc) y el archivo mapa.txt que acabas de guardar (s, es preferible que ambos estn en el mismo directorio). Una vez all, ejecuta esto en el terminal: $ ./txt2plmap mapa.txt Si todo ha ido bien, por la pantalla te saldr el cdigo Prolog que el conversor te habr generado a partir de tu mapa. Si hay algn error, vers un mensaje de error indicndote dnde te has equivocado. Corrige todos los errores que encuentres y, cuando la conversin termine con xito, haz esto para generar el archivo de cdigo prolog: $ ./txt2plmap mapa.txt > mapa.pl De esta forma, redirigirs lo que antes sala por la pantalla a un archivo llamado mapa.pl donde tendrs tu mapa. 5. Abre el mapa en cdigo Prolog y adele el aspecto y comportamientos de tus objetos y personajes. Ahora debers abrir el archivo mapa.pl y modificar las partes que sean necesarias y aadir tus propias reglas para implementar los comportamientos de tus objetos y personajes. Con esto puedes hacer lo que quieras, pero tendrs que programrtelo t, que el conversor no da para tanto :). Para ms detalles sobre qu modificar o cmo programar tus comportamientos consulta la seccin Aadiendo vida a los mapas. 6. Comprueba que todo en tu mapa funciona correctamente. Para esto, llvate el archivo mapa.pl a la carpeta donde est el juego pl-man y lanza el juego con tu mapa para ver qu sucede. Para realizar esto, debes crear primero un fichero solucin (lo llamaremos -3-

solucion.pl) de prueba con 2 instrucciones bsicas que te permitir probar el mapa. Lo puedes crear en el gedit, y tendr el siguiente contenido: :- use_module('pl-man-game/main'). miregla. La primera lnea permite usar los comandos de pl-man, y debe aparecer en cualquier fichero solucin que creemos. La segunda representa simplemente el nombre de la regla que se usar para resolver el mapa. Una vez creado el fichero solucin de prueba, y situados en el terminal en la carpeta donde se encuentra el juego pl-man, probamos el mapa generado mediante el siguiente comando: $ ./plman mapa.pl solucion.pl miregla Debera aparecer una ventana como la siguiente:

Figura 1. Ventana de ejemplo de ejecucin de Pl-Man.

-4-

2. Detalles a la hora de dibujar tu mapa


Tus neuronas se activan a una velocidad de vrtigo generando la imagen de un mapa nuevo. Lo ves claro: ya tienes el mapa definitivo. Te sientas en el PC, abres tu editor de textos favorito y te dispones a plasmar la imagen de tu mapa sobre un archivo de texto. En ese momento te das cuenta: Cmo se dibuja un mapa con el editor de textos? Esta es tu seccin. Lo primero de todo, unas consideraciones. Llamamos mapa a una matriz 2D discreta donde cada elemento de la matriz representa una regin del espacio donde puede haber un nico elemento. Traducindolo para que lo veas claro. Debera ser algo similar a esto:

#################### #..........E.......# #..####.....####...# #.O................# #....####@####.....# #.##...........##..# #.##...####....##..# #..................# #################### Figura 2. Ejemplo de mapa en formato txt. Cada uno de los caracteres que hay en ese archivo representa el contenido de una celda del mapa, o lo que es lo mismo, lo que habr en esa posicin en el mundo de pl-man. En este mapa de ejemplo hay paredes (#), cocos (.), un enemigo (E), un objeto (O) y pacman (@). As pues, dibujar un mapa es tan sencillo como rellenar el archivo de texto con caracteres como los del ejemplo, en el orden que consideres oportuno. Por supuesto, no vale cualquier archivo de texto. El archivo deber cumplir unas condiciones para que sea aceptado por la utilidad de conversin y que funcione en pl-man. Lee con atencin las reglas: 1. Es obligatorio que haya un pacman (@) y slo uno en todo el mapa, ya que esto indica la posicin inicial desde donde partir el protagonista. 2. Debe haber por lo menos 1 coco (.) en todo el mapa. Por supuesto, puedes poner tantos como quieras, pero no puedes hacer un mapa sin cocos, ya que el objetivo de pacman siempre es comrselos todos. 3. El mapa debe ser rectangular. Debe haber el mismo nmero de caracteres en cada una de las lineas del archivo de texto. Esto es muy importante, ya que los espacios e intros tambin cuentan. Una linea que tenga espacios al final ser indicada por el conversor como un error si tiene ms caracteres que las anteriores. De igual forma, los intros al final del archivo darn lugar a errores porque sern considerados como filas con 0 caracteres. Por supuesto, no todos los caracteres que uses tienen el mismo significado. Como has podido deducir de lo anterior, hay una serie de caracteres con significados especiales. Aqu tienes el detalle de lo que significa cada carcter: -5-

'@' Posicin inicial de pacman en el mapa. Debe haber obligatoriamente 1 y slo 1. '.' Coco. Tiene que haber al menos 1 en el mapa. 'E' Posicin de salida de un enemigo. Se trata de una entidad de tipo mortal (que puede
matar a pacman) y que tendr vida propia. Esto define su posicin inicial en el mapa. Es trabajo tuyo definir despus las reglas que gobiernen su comportamiento.

'O' Posicin de un objeto. Una entidad de tipo object. Por defecto tienen las propiedades

not_solid (que no es slido, por lo que puede ser atravesado) y not_static (que no es esttica, por lo que puede ser cogido). Al igual que con los enemigos, es cosa tuya definir las reglas que gobiernen su funcionamiento.

'' Espacio en blanco. Un lugar en el mapa donde inicialmente no hay nada.

Adems de estos caracteres especiales, puedes utilizar cualquier otro carcter que se te ocurra. Cualquier otro que pongas en el archivo de texto del mapa (por ejemplo, #), ser considerado como una pared (un slido que no puede ser cogido). Un ltimo detalle. Cada objeto y entidad del juego tiene una representacin, un carcter que lo va a representar cuando el mapa se dibuje. En el archivo .pl del mapa, cuando se aaden objetos y entidades se especifica la apariencia que tiene cada objeto o entidad. Los objetos (O) y enemigos (E) que defines en el archivo de texto son convertidos en entidades en el archivo .pl con los caracteres 'O' y 'E' como aspecto por defecto. Podrs darle a cada objeto o enemigo un aspecto propio cuando edites el archivo .pl, con slo cambiar el carcter que los representa. En la siguiente seccin podrs ver cmo hacer esto.

-6-

3. Aadiendo vida a los mapas


Una vez superado el sndrome de la pgina en blanco tendrs creado un mapa y lo habrs convertido a cdigo Prolog utilizando la utilidad de conversin de mapas. Si tu mapa no tiene objetos ni personajes enemigos, tu trabajo habr terminado. Sin embargo, cualquier cosa que hayas aadido con la que se pueda interactuar necesitar que especifiques sus propiedades y que implementes sus comportamientos. En esta seccin veremos cmo hacer esto.

3.1.Conociendo el formato de archivo de cdigo de Prolog


Para empezar, vamos a seguir con el mapa de ejemplo que hemos visto anteriormente en la Figura 2. A continuacin tenemos el cdigo Prolog que nos genera el conversor a partir de ese mapa:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%PrologCodeforMapfilegeneratedfrommapa.txt %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

map_format_version(1.0).
map([['#','#','#','#','#','#','#','#','#','#','#','#','#','#', '#','#','#','#','#','#'], ['#','.','.','.','.','.','.','.','.','.','.','.','.','.','.', '.','.','.','#'], ['#','.','.','#','#','#','#','.','.','.','.','.','#','#','#', '#','.','.','.','#'], ['#','.','.','.','.','.','.','.','.','.','.','.','.','.','.', '.','.','.','#'], ['#','.','.','.','.','#','#','#','#','','#','#','#','#','.', '.','.','.','.','#'], ['#','.','#','#','.','.','.','.','.','.','.','.','.','.','.', '#','#','.','.','#'], ['#','.','#','#','.','.','.','#','#','#','#','.','.','.','.', '#','#','.','.','#'], ['#','.','.','.','.','.','.','.','.','.','.','.','.','.','.', '.','.','.','.','#'], ['#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#', '#','#','#','#']]).

map_size(20,8). num_dots(95). pacman_start(9,4). initMap: addSolidObject('#'),

-7-

createGameEntity(OID_0,'O',object,2,3,inactive,norule, [name('ObjectName'),solid(false),static(false), use_rule(norule), description('ObjectDescription'), appearance(attribs(normal,default,default))]), createGameEntity(EID_0,'E',mortal,11,1,active,norule, [appearance(attribs(normal,default,default))]). norule(_). norule(_,_,_,_,_).

Figura 3. Cdigo generado al convertir el mapa a Prolog. Vamos a analizar cada uno de los hechos y reglas que nos genera el conversor para saber cmo funciona este cdigo. En primer lugar, tenemos el hecho map_format_version/1 que nos indica la versin de formato de mapa con la que estamos trabajando (en este caso, la 1.0). Despus, aparece el hecho map/1 qu, como se ve en el cdigo, contiene la conversin del mapa a una lista de listas de caracteres. El hecho es casi una transcripcin literal de los caracteres del archivo de texto uno a uno, con algunas pequeas modificaciones. Por ejemplo, pacman, los objetos y los enemigos no aparecen en map/1, y han sido sustituidos por espacios. Esto es as porque las entidades del mundo se crean usando createGameEntity/8, como veremos despus. A continuacin de la definicin del mapa, tenemos los siguientes 3 hechos:

map_size/2

Define el tamao del mapa, en ancho y alto. En nuestro caso, 20,8, es decir, 20 columnas y 8 filas, que se manejarn siempre empezando desde la 0. Indica cuantos cocos (dots) hay en total en el mapa. Indica la posicin inicial desde donde partir nuestro pacman. En nuestro caso, es la 9,4 (columna 9, fila 4)

num_dots/1 pacman_start/2

Un detalle muy importante de estos hechos, ms all de su significado, es el hecho de que son calculados en el momento de convertir el mapa, y utilizados directamente por el juego. Esto significa que, en caso de que se te ocurra modificar el contenido de map/1(es decir, la definicin del mapa) ser imprescindible que actualices correctamente estos 3 hechos. De lo contrario, tu mapa podra no funcionar correctamente. Mi recomendacin personal es que modifiques el archivo de texto y vuelvas a generar el cdigo Prolog con el conversor. As te asegurars que no te equivocas. La parte central del archivo del mapa es la regla initMap/0. Esta regla es de vital importancia ya que es llamada por el juego nada ms cargar el mapa en memoria. El objetivo de esta regla es realizar todas las operaciones necesarias para inicializar el mapa. Se puede hacer en ella cualquier cosa que se considere oportuna, como hacer rectracts y asserts de predicados dinmicos que deben inicializarse, por ejemplo. Esta regla es la responsable de definir las paredes del mapa y crear las entidades iniciales (objetos y enemigos). Estas dos tareas se hacen lanzando las reglas addSolidObject/1 y createGameEntity/8, que a continuacin se explican con detalle:

addSolidObject(Obj)
-8-

Obj: Carcter que define la apariencia del objeto que debe ser considerado como slido. Aade a la base de conocimientos del juego un nuevo carcter Obj que ser considerado como slido, es decir, como pared. Por lo tanto, al comienzo de initMap/0 es imprescindible lanzar esta regla una vez por cada carcter que tenga que ser considerado como pared en el juego.

createGameEntity(EID,Ap,Type,X,Y,Active,ControlRule,Data)
EID: Identificador de la entidad (nmero entero que la representa). Ap: Apariencia de la entidad (carcter que debe ser pintado). Type: Tipo de entidad. Puede ser: pacman, object, mortal o solid. X, Y: Coordenadas X, Y dnde debe ser posicionada inicialmente la entidad. Active: Atributo que indica si la entidad est activa (active) o no (inactive). Las entidades activas son aquellas que en cada ciclo procesan y toman decisiones. Es decir, las entidades que estn activas tendrn una regla que ser llamada 1 vez por cada ciclo de ejecucin del juego. ControlRule: Regla de control. Este es el nombre de la regla que controla el comportamiento de la entidad. Esta regla ser llamada 1 vez por cada ciclo de ejecucin para permitirle a la entidad que realice las acciones que crea convenientes. La regla de control, cuando sea llamada, recibir como primer y nico parmetro el nmero identificador de la entidad para la que es llamada (EID: Entity Identifier). De este modo, muchas entidades diferentes podrn compartir la misma regla (el mismo comportamiento). Data: Datos adicionales especficos de la entidad, en forma de lista de propiedades y valores. Las entidades de tipo mortal (los enemigos), no tienen asociado nada en este campo por defecto. Los objectstienen ms informacin especfica de los objetos. Esta regla crea una nueva entidad en el entorno del juego y la posiciona en un lugar determinado, con todos sus parmetros e informacin asociada. Se utiliza fundamentalmente para crear objetos y enemigos. Es importante destacar que los objetos tienen un campo Data especfico para ellos. A continuacin describimos los detalles de dicho campo, en cuanto a las propiedades (y sus correspondientes valores) que pueden formar parte de la lista:

Nombrename(ObjectName)
Nombre del objeto. Es el nombre propio de los objetos, utilizado para identificarlos.

Tiposolid(Bool),not_solid(Bool)
Tipo de objeto. Hay 2 tipos: solid y not_solid. Los objetos de tipo solid se consideran slidos como las paredes, de modo que pacman no puede pasar por donde haya uno objeto de tipo solid. Los objetos not_solid, por contra, no son slidos, y pacman puede transitar por una casilla donde haya un objeto de este tipo. Bool ser true o false.

Estadostatic(Bool),not_static(Bool)
Estado del objeto. Hay 2 tipos: static, not_static. Los objetos static no pueden ser cogidos ni usados por ninguna entidad, mientras que los objetos not_static pueden ser cogidos, -9-

dejados y usados por cualquier entidad del juego. Bool puede valer true o false.

Reglause_rule(Rule)
Regla de uso del objeto. Este campo contiene el nombre de una regla que el juego lanzar cuando una entidad lleve consigo el objeto y decida usarlo. La regla recibir 4 parmetros: (EID,X,Y, DIR). EID (Entity Identifier) es el identificador de la entidad que pretende usar el objeto. X e Y corresponden a la posicin del mapa donde se va a hacer uso del objeto. DIR indica la direccin en la que se va a hacer uso del objeto (up, down, left o right).

Descripcindescription(ObjectDescription)
Cadena de texto con la descripcin del objeto.

Aparienciaappearance(attribs(Atributo,TextColor,BGColor))
Apariencia del objeto en base a 3 atributos o propiedades. Atributoespecifica el estilo para el carcter que representa al objeto (normal,bold,faint,underline,...). TextColor establece el color de la fuente en la que se pinta dicho carcter (black,red, green,yellow,magenta,cyan,white,default). BGColor expresa el color de fondo para dicho carcter, pudiendo ser cualquiera de los mencionados anteriormente. TextColor y BGColor pueden tener el valor default, que representa el color por defecto (green). Finalmente, el conversor genera 2 hechos norule(_). y norule(_,_,_,_,_).. Estos hechos son en realidad la regla norule que no hace nada. Representan la regla de control por defecto para las entidades creadas por el conversor. Una vez hayas creado tus propias reglas para tus entidades podrs borrarlas tranquilamente, ya que no tendrn utilidad.

3.2. Modificando el cdigo del mapa


A la hora de modificar el cdigo del mapa hay infinitas cosas que podramos incorporar. Como es todo cdigo Prolog, cualquier cosa que imagines puedes hacerla (aunque algunas te costarn ms que otras, claro :)). En cualquier caso, hay una serie de cosas que no debes olvidar hacer primero. Estas cosas son las siguientes: 1. Modifica las apariencias de los objetos y enemigos que hayas definido. Slo tienes que cambiar el carcter que aparece en el primer argumento de los objetivos createGameEntity para poner el que ms te guste. 2. Definir reglas de comportamiento para tus objetos y enemigos activos. Puedes utilizar comportamientos predefinidos o propios. En principio definirs una regla para cada objeto y enemigo activo. Un buen punto de partida son los comportamientos predefinidos, de los que hablaremos en el siguiente punto. Una vez visto esto ya estaremos en condiciones de crear nuestros propios comportamientos. Esto lo explica de forma detallada el punto 5. 3. Enlaza cada objeto y enemigo con su regla de control, sea propia o predefinida. Para esto slo tienes que ir al 7 parmetro de cada objetivo createGameEntity y sustituir norule por el nombre de la regla que hayas creado para ese enemigo u objeto. Ojo! Ten en cuenta que la regla slo ser llamada si el 6 parmetro contiene el tomo active. Este tomo indica que el objeto o enemigo es una entidad activa y que debe usar la regla de control en cada ciclo para moverse. En caso de que el objeto o enemigo no vayan a ser activos no hay porqu definirles una regla de control. Basta con dejar ese 6 parmetro como inactive. 4. Establece las propiedades de los objetos. El 8 parmetro de los objetivos createGameEntity de los objetos contiene todas las propiedades de los objetos en una - 10 -

lista de propiedades y valores (campo Data). Dentro de ella debes ponerle un nombre nico a cada objeto (hecho name), una descripcin textual del objeto (en el hecho description, una cadena de texto entre comillas simples), y tambin puedes modificar su apariencia (en el hecho appearance, su estilo, color de texto y de fondo, tal y como hemos mencionado anteriormente). Adems, debes decir si el objeto es solid o not_solid (indica si se puede transitar por donde est el objeto o no) y si es static o not_static (indica si el objeto puede cogerse o no). Por ltimo, la regla de uso del objeto, lo tratamos en el siguiente punto. 5. Crea una regla de uso propia o predefinida para cada objeto que pueda ser usado. Los objetos que pueden ser usados (por ejemplo una llave o una pistola) necesitan una regla que defina lo que ocurrir cuando el objeto sea usado. Puedes usar una regla predefinida (segn el comportamiento) o definir una para cada objeto. Del uso de reglas de comportamientos predefinidos hablaremos posteriormente. Si la defines t debes acordarte de ponerle a la regla los 5 argumentos que necesita: ObjID, EID, X, Y, DIR. ObjId (Object Identifier) es el identificador del objeto que est siendo utilizado. EID (Entity Identifier) es el identificador de la entidad que intenta utilizar el objeto. X e Y indican el lugar exacto donde quiere hacerse uso del objeto. DIR indica en qu direccin se hace uso del objeto (up, down, left, right). Por ejemplo, un personaje que est en la posicin (1,1) puede hacer uso de una pistola en la posicin (1,2) con direccin down, lo que quiere decir que habr disparado hacia abajo. 6. Enlaza tus objetos usables con sus respectivas reglas de uso, propia o predefinida. Para esto ltimo slo tienes que ir al hecho use_rule(norule) del campo Data, dentro de los objetivos createGameEntity de cada objeto. Sustituye ah norule por el nombre de la regla que hayas creado para ese objeto. Una vez hayas hecho estos pasos, ya tienes listo tu mapa. El mapa debera funcionar tal cual lo tienes definido ahora mismo, as que prubalo lanzando el entorno y observa si las cosas bsicas van como debes. Para probarlo te puede venir bien usar la regla keyControlledPacman en lugar de randomPacman. Con esta regla puedes controlar al pacman con el teclado y hacer pruebas. Las teclas para controlar a Pacman son las siguientes:

moverse

(arriba, abajo, izquierda, derecha) = (Q, A, O, P)

coger objeto(arriba, abajo, izquierda, derecha) = (W, S, L, ) dejar objeto (arriba, abajo, izquierda, derecha) = (E, D, :, -) usar objeto (arriba, abajo, izquierda, derecha) = (R, F, 9, 0)

La forma de probar el mapa a travs de esta regla es a travs del siguiente comando (una vez situados en un terminal en la carpeta donde se encuentra el juego Pl-Man): $ ./plman mapa.pl -s playerRules.pl keyControlledPacman -d 0 Prueba a mover a tu pacman por el mapa, a coger los objetos que puede y que no puede coger, a intentar coger un enemigo, a atravesar los objetos slidos y los no slidos. Prubalo todo y comprueba si est todo bien definido. Una vez est todo bien probado, podemos pasar a lo realmente interesante: a programar comportamientos :).

- 11 -

4.Utilizando comportamientos predefinidos


Para crear las reglas de control de tus objetos y enemigos activos, y las reglas de uso de objetos, dispones de la posibilidad de usar comportamientos que ya estn predefinidos. A continuacin tenemos una breve descripcin de los mismos:

arithmeticDoor automaticArcher basicDoorKey basicTeletransport combiner enemyBasicMovement enemyFollower entitySequentialMovement gunBasic launchBall mineExplosion pushBlocks quantumJump respawnPoint soccerGoal spiderGhost Para usar cualquiera de estos comportamientos debes seguir los pasos siguientes: 1) Cargar el fichero correspondiente al comportamiento predefinido. Esto se realiza mediante la regla load_behaviour/1 colocndola al comienzo del fichero mapa.pl.

load_behaviour(Name).
Carga el comportamiento de nombre Name, siendo Name uno de los indicados anteriormente. 2) Definir la regla de control o de uso del objeto para la entidad de la que se trate, a travs de la regla correspondiente a dicho comportamiento. Normalmente el nombre de dicha regla coincide con el del comportamiento, y controlar el comportamiento de dicha entidad.

Nombre_Regla(Param1,Param2,...,ParamN).
La lista de parmetros Param1,Param2,...,ParamN depende de cada comportamiento. Posteriormente detallamos un ejemplo de uso de dicha regla para cada uno de los comportamientos predefinidos. 3) Enlazar cada objeto con su regla de uso y objeto o enemigo con su regla de control de comportamiento. Esto se corresponde con los puntos 3 y 5 de modificacin del cdigo del mapa comentados anteriormente. A continuacin vemos ejemplos de enlaces para cada uno de los comportamientos.

- 12 -

arithmeticDoor: implementa el comportamiento de una puerta que tiene una operacin aritmtica implcita. Para abrir la puerta ser necesario usar en ella una llave vlida, que ser un objeto con la apariencia del nmero que representa el resultado de dicha operacin. Incluye una subregla para la creacin de un conjunto de llaves no vlidas (nmeros distintos del resultado de dicha operacin) que se situarn aleatoriamente en el mapa (arithmeticDoor(createRamdomKeys,...)). Incluye la regla arithmeticDoor/6 que permite definir una puerta aritmtica (operador +,-,*,/) y asociarla a los 3 objetos que representan a los 2 operandos y al resultado de dicha operacin (nica llave vlida), y algunos parmetros de comportamiento. Tendremos el objeto puerta, los 2 objetos operando, el objeto resultado y un conjunto de nmeros aleatorios (llaves no vlidas) ya creados mediante la regla createGameEntity/8. Al objeto puerta habr que asociarle la regla siguiente:

arithmeticDoor(init,OID_OP,OID_N1,OID_N2,RESULT,L_PARAMS)
OID_OP: Identificador del objeto que representa a la puerta aritmtica. OID_N1: Identificador del objeto que representa al operando 1. OID_N2: Identificador del objeto que representa al operando 2. RESULT: Este parmetro se unifica con el resultado de la operacin aleatoria para la puerta aritmtica (nica llave vlida que la abrir). L_PARAMS: Parmetros para controlar la forma en que se comporta la puerta aritmtica

operators(LIST): la puerta slo usa los operadores que estn en la lista LIST.

La creacin del conjunto de llaves no vlidas se realiza mediante la subregla arithmeticDoor(createRamdomKeys,...)):

arithmeticDoor(createRamdomKeys,OID_OP,NUMKEYS, location(X,Y),L_KEYS,L_PARAMS)
OID_OP: Identificador del objeto que representa a la puerta aritmtica al que se asociarn las llaves. NUMKEYS: Nmero de llaves no vlidas a crear de forma aleatoria. X,Y: Coordenadas donde se crean las llaves (podran ser rnd(A,B) y rnd(LIST)). L_KEYS: Lista de OIDs de las llaves creadas aleatoriamente. L_PARAMS: Parmetros para controlar la forma en que se comporta el creador de llaves aleatorias.

distributed: asegura que cada llave creada se ubicar en una posicin vaca (donde no haya ningn objeto). add_properties(LIST): La lista de llaves se aade a la lista de propiedades de cada nueva llave creada.

Ejemplo de uso: Queremos crear una puerta aritmtica con un operador aleatorio de entre +,-,/ (en la posicin 5,2 y representada con el carcter del operador aleatorio) que slo pueda ser abierta con un objeto de nombre 'llave_aritmetica', situado en la posicin 10,6, representado por el resultado de la operacin, en negrita y color azul (est definido al final). Para ello creamos primero los 3 objetos operador y operandos mediante la regla createGameEntity/8. A continuacin asociamos esos 3 objetos y definimos dicho comportamiento a travs de la regla arithmeticDoor/6 (init). Despus creamos un conjunto de 4 llaves no vlidas situadas aleatoriamente dentro del intervalo de - 13 -

coordenadas [1,16], [5,17], tambin con la regla arithmeticDoor/6 (createRamdomKeys). Estas llaves tendrn color azul (al igual que la llave vlida) y no habr posibilidad de que 2 de ellas se siten en la misma posicin del mapa (parmetro distributed).
createGameEntity(OID_OP,'+',object,5,2,inactive,norule, [name(operador),solid(true),static(true),use_rule(norule), description('Puertaoperador'),appearance(normal,default,default)]), createGameEntity(OID_N1,1,object,4,2,inactive,norule, [name(numero1),solid(true),static(true),use_rule(norule), description('Primeroperando'),appearance(normal,default,default)]), createGameEntity(OID_N2,2,object,6,2,inactive,norule, [name(numero2),solid(true),static(true),use_rule(norule), description('Segundooperando'),appearance(normal,default,default)]), arithmeticDoor(init,OID_OP,OID_N1,OID_N2,RES,[operators(['+','','/'])]), arithmeticDoor(createRamdomKeys,OID_OP,4,location(rnd(1,16),rnd(5,7)),_, [distributed,add_properties([appearance(bold,cyan,default))])]), createGameEntity(OID_KEY,RES,object,10,6,inactive,norule, [name(llave_aritmetica),solid(false),static(false), use_rule(arithmeticDoorKey), description('Objetollaveparapuertaaritmtica'), appearance(bold,cyan,default)]).

Como podemos observar, los objetos operador, numero1 y numero2 no tienen asociada la regla arithmeticDoor. sta slo se aplica a las llaves implicadas, tanto a las vlidas (en este caso, llave_aritmetica) como a las que no sirven (las generadas por createRamdomKeys). Tambin podemos destacar que dichos 3 objetos son solid (no se puede atravesar) y static (no se puede coger), por lo que la nica manera de pasar por ellos ser usando en el objeto operador la llave_aritmetica. Los restantes objetos 'llave_aritmetica' y las llaves no vlidas se pueden atravesar y coger. De esta forma, si pacman intenta usar una llave no vlida en el objeto operador, aparecer un mensaje indicando que 'No puedes usar es llave ah'. Otro detalle: todos ellos son inactive puesto que no tienen una regla de control asociada, solamente una de uso que es arithmeticDoor. En ella podemos ver que el segundo parmetro es el identificador de la entidad que representa el objeto 'operador', que el tercer y cuarto parmetros son los identificadores de las entidades que representan a los operandos numero1 y numero2, que el quinto parmetro especifica el resultado de la operacin aritmtica que se asocia con la apariencia del objeto que representa la llave vlida (parmetro RES) y que en el sexto parmetro se indican los 3 posibles valores para el operador (+,-,/).

automaticArcher: crea un objeto que dispara flechas de forma automtica con el objetivo de matar a pacman, como un arquero. Incluye la regla automaticArcher/6 que permite definir un arquero, la lista de entidades a las que disparar, la direccin de disparo, el retraso entre 2 disparos, su comportamiento y apariencia de las balas. Tendremos un objeto arquero creado mediante la regla createGameEntity/8, al que habr que asociarle la regla siguiente:

automaticArcher(init,OID,L_AIM,DIR,DELAY,L_PARAMS).
OID: Identificador del objeto que representa al arquero. - 14 -

L_AIM: Lista de entidades a las que disparar el arquero cuando tenga contacto visual con ellas. DIR: Direccin de disparo (up, down, left, right). DELAY: Nmero de ciclos de ejecucin de retraso entre 2 disparos. L_PARAMS: Parmetros para controlar la forma en que se comporta el arquero y su apariencia

continuous: dispara de forma continua cada DELAY ciclos de ejecucin. Por defecto, slo dispara si ve un objetivo que pertenezca a L_AIM. randomFirstShot: Define un nmero aleatorio de ciclos de ejecucin de espera antes de realizar el primer disparo. bullet_appearance(AP): AP es el carcter que representa las balas. bullet_appearance(AP, ATR, TC, BC): Extensin de la apariencia de las balas. AP: carcter; ATR: Estilo; TC: Color de la fuente; BC: Color de fondo

Ejemplo de uso: Queremos crear un arquero (en la posicin 5,2, representado con el carcter '>' en negrita y con color amarillo), que disparar a Pacman cuando lo vea a su derecha cada 2 ciclos de ejecucin, con balas representadas con el carcter '-' en negrita y color rojo. Para ello definimos dicho objeto arquero a travs de la regla createGameEntity/8 y su comportamiento a travs de la regla de uso automaticArcher/6.
createGameEntity(OID_ARCH,'>',object,5,2,active,norule, [name(arquero),solid(false),static(true),use_rule(automaticArcher), description('ArquerodelRey'),appearance(bold,yellow,default)]), automaticArcher(init,OID_ARCH,['@'],right,2, [bullet_appearance('',bold,red,default)]).

Destacar que el objeto arquero es not_solid (se puede atravesar, dado que si no es as, las balas creadas se destruiran automticamente porque primero alcanzaran al arquero), static (no se puede coger) y active para que dispare desde el comienzo de forma automtica.

basicDoorKey: controla el comportamiento de una puerta y el conjunto de llaves disponibles para abrirla. Se trata de un comportamiento asociado al uso de objetos. Incluye la regla basicDoorKey/4 que permite definir una puerta y las llaves que la abren. Tendremos un objeto puerta y tantos objetos llaves creados mediante la regla createGameEntity/8. Los objetos llave pueden servir para abrir la puerta o no, pero a todos ellos habr que asociarles la regla siguiente:

basicDoorKey(init,OID,ON_OPEN,KEYLIST)
OID: identificador del objeto que representar la puerta (en este caso). ON_OPEN: Lista de acciones a realizar cuando se abra la puerta. Puede ser cualquiera de las acciones permitidas por Pl-Man. KEYLIST: Lista de identificadores de los objetos (llaves) que pueden abrir la puerta. Ejemplo de uso: Queremos crear una puerta (en la posicin 1,4 y representada con el carcter '/' en color negro y fondo verde) que slo pueda ser abierta con un objeto de nombre 'llave_azul (en la - 15 -

posicin 8,5 y representado por el carcter '-' en color azul), y que la llave y la puerta desaparezcan cuando sta ltima se abra. Tambin tenemos un objeto llamado 'llave_roja' (en la posicin 12,8 y representado tambin por el carcter '-' pero en color rojo) que no abrir dicha puerta. Para ello definimos los 3 objetos a travs de la regla createGameEntity/8 y el comportamiento de la puerta a travs de la regla de uso basicDoorKey/4.
createGameEntity(OID_D,'/',object,1,4,active,norule, [name(puerta),solid(true),static(true),use_rule(norule), description('Puertaqueseabreconlallaveazul'), appearance(normal,black,green)]), createGameEntity(OID_A,'',object,8,5,inactive,norule, [name(llave_azul),solid(false),static(false),use_rule(basicDoorKey), description('LlaveAzul'),appearance(normal,cyan,default)]), createGameEntity(OID_R,'',object,12,8,inactive,norule, [name(llave_roja),solid(false),static(false),use_rule(basicDoorKey), description('LlaveRoja'),appearance(normal,red,default)]), basicDoorKey(init,OID_D,['plman':destroyGameEntity(OID_D), 'plman':destroyGameEntity(OID_A)],[OID_A]).

Como podemos observar, el objeto 'puerta' no tiene asociada la regla basicDoorKey. sta slo se aplica a las llaves implicadas, tanto a las tiles (en este caso, llave_azul) como a las que no sirven (llave_roja). Tambin podemos destacar que el objeto 'puerta' es solid (no se puede atravesar) y static (no se puede coger), por lo que la nica manera de pasarlo ser usando en l la llave azul. Los objetos 'llave_azul' y 'llave_roja' se pueden atravesar y coger. Otro detalle: todos ellos son inactive puesto que no tiene una regla de control asociada, solamente una de uso que es basicDoorKey. En ella podemos ver que el segundo parmetro es el identificador de la entidad que representa el objeto 'puerta', en el tercer parmetro que las 2 acciones asociadas a la apertura de la puerta (destruir tanto la puerta como la llave azul) se realizan a travs de la regla destroyGameEntity/1, que slo recibe como parmetro el identificador de la entidad a destruir (en este caso, OID_D -puerta- y OID_A llave_azul-) y que el cuarto parmetro est compuesto nicamente por el identificador de la entidad que especifica la nica llave que abre la puerta (OID_A). De esta forma, si pacman intenta usar la llave roja en esta puerta, aparecer un mensaje indicando que 'No puedes usar Llave Roja ah'.

basicTeletransport: controla el comportamiento de un objeto de teletransporte. Incluye la regla basicTeletransport/6 que permite definir una puerta de teletransporte a otro lugar del mapa. Tendremos el objeto creados mediante la regla createGameEntity/8, al que habr que asociarle la regla siguiente:

basicTeletransport(init,OID,from(X1,Y1),to(X2,Y2),L_TRANS, L_PARAMS)
OID: identificador del objeto que representar la puerta. X1,Y1: Coordenadas del origen del tnel de teletransporte. X2,Y2: Coordenadas del destino del tnel de teletransporte. L_TRANS: Lista de entidades que pueden usar el teletransporte (por su apariencia). KEYLIST: Parmetros que controlan el comportamiento del teletransporte. - 16 -

- viceversa: Habilita el teletransporte de vuelta de destino a origen. Ejemplo de uso: Queremos crear un objeto de teletransporte (en la posicin 5,2 y representado por el carcter '?' de color negro y fondo verde) a la posicin 1,1 que slo podr usar pacman y que podr utilizarse tambin en sentido inverso.
createGameEntity(OID_TT,'?',object,5,2,active,basicTeletransport, [name(teletransporte),solid(false),static(true),use_rule(norule), description('Teletransporte'),appearance(normal,black,green)]), basicTeletransport(init,OID_TT,from(5,2),to(1,1),['@'],[viceversa]).

Destacar que el objeto teletransporte es not_solid (se puede atravesar, obviamente para que se pueda entrar en l) y static (no se puede coger). Asimismo es active puesto que tiene asociada la regla de control basicTeletransport/6.

combiner: combina varios comportamientos que pueden ser ejecutados por la misma entidad. No requiere inicializacin.

Ejemplo de uso: Queremos crear un enemigo en la posicin 11,1 y representado por el carcter 'E' de color rojo que combine 2 comportamientos al mismo tiempo: por un lado, perseguir a pacman y por otro, le disparar flechas.
createGameEntity(EID,'E',mortal,11,1,active, combiner([enemyFollower,automaticArcher]), [appearance(attribs(normal,red,default))]), enemyFollower(init,EID,...), automaticArcher(init,EID,...).

Destacar que el enemigo es mortal y active para que est activo en todo momento segn los comportamientos que especifique la regla combiner. Recordar que ser necesario cargar los ficheros correspondientes a los comportamientos que se combinen mediante la regla load_behaviour.

enemyBasicMovement: controla el comportamiento de un enemigo (o entidad mvil) que se mueve de izquierda a derecha o de arriba a abajo. Incluye la regla enemyBasicMovement/4, que permite definir un movimiento bsico para un enemigo o entidad mvil. Tendremos tantos enemigos o entidades mviles creados mediante la regla createGameEntity/8. A todos los que se quiera aplicar un comportamiento de este tipo habr que asociarles la regla siguiente:

enemyBasicMovement(init,EID,MOVE_TYPE,LIMITS)
EID: identificador de la entidad que ser controlada. MOVE_TYPE: Tipo de movimiento a realizar. Puede ser de arriba hacia abajo (updown) o viceversa (down-up), de izquierda a derecha (left-right) o viceversa (rightleft). LIMITS: Lista de objetos que hacen que la entidad cambie su direccin de movimiento cuando entran en su ngulo de visin. Ejemplo de uso: Queremos crear un enemigo (en la posicin 11,1 y representado por el carcter 'E' de color rojo) que se mueva de izquierda a derecha inicialmente y que cambie la direccin de - 17 -

movimiento cuando vea una '#' o un '|'.


createGameEntity(EID,'E',mortal,11,1,active,enemyBasicMovement, [appearance(attribs(normal,red,default))]), enemyBasicMovement(init,EID,leftright,['#','|']).

Destacar que el enemigo es mortal y active para que est activo en todo momento segn el comportamiento definido por la regla enemyBasicMovement.

enemyFollower: controla el comportamiento de un enemigo (o entidad mvil) para que persiga a pacman o a otro tipo de entidad. Incluye la regla enemyFollower/5, que permite definir para un enemigo o entidad mvil un movimiento de persecucin a pacman o a cualquier otro tipo de entidad. Tendremos tantos enemigos o entidades mviles creados mediante la regla createGameEntity/8. A todos los que se quiera aplicar un comportamiento de este tipo habr que asociarles la regla siguiente:

enemyFollower(init,EID,L_FOLLOW,L_DIRS,L_PARAMS)
EID: identificador de la entidad que ser controlada. L_FOLLOW: Lista con los identificadores de las entidades que sern perseguidas. L_DIRS: Lista con las direcciones de persecucin. L_PARAMS: Lista de posibles modificadores delay(N): dejar N ciclos de ejecucin de retraso entre movimientos. Ejemplo de uso: Queremos crear un enemigo (en la posicin 11,1 y representado por el carcter 'E' de color rojo) que perseguir a pacman si le tiene a la vista hacia arriba o abajo. Adems, permanecer detenido 2 ciclos de ejecucin despus de cada movimiento que haga.
createGameEntity(EID,'E',mortal,11,1,active,enemyFollower, [appearance(attribs(normal,red,default))]), enemyFollower(init,EID,['@'],[up,down],[delay(2)]).

Destacar que el enemigo es mortal y active para que est activo en todo momento segn el comportamiento definido por la regla enemyFollower.

entitySequentialMovement: controla el comportamiento de un enemigo (o entidad mvil) para que se mueva siguiendo una secuencia de movimientos predefinida. Incluye la regla entitySequentialMovement/4, que permite definir una secuencia de movimientos predefinida para un enemigo o entidad mvil. Tendremos tantos enemigos o entidades mviles creados mediante la regla createGameEntity/8. A todos los que se quiera aplicar un comportamiento de este tipo habr que asociarles la regla siguiente:

entitySequentialMovement(init,EID,MOVE_LIST,MODIFIERS)
EID: Identificador de la entidad que ser controlada. MOVE_LIST: Lista de movimientos a realizar. MODIFIERS: Lista de tomos que permiten expresar modificaciones al comportamiento estndar - no_repeat_moves: Por defecto siempre se chequea que los movimientos sean ejecutados de forma efectiva. Si no sucede, se repiten. Este modificador desactiva - 18 -

esta caracterstica. - no_cycle: Por defecto, cuando una entidad ha realizado todos los movimientos de su lista, el ciclo se repite. Este modificador desactiva esta posibilidad. Ejemplo de uso: Queremos crear un enemigo (en la posicin 11,1 y representado por el carcter 'E' de color rojo) que perseguir a pacman realizando los movimientos de la lista. Una vez que los ha hecho todos, comenzar de nuevo el ciclo.
createGameEntity(EID,'E',mortal,11,1,active,entitySequentialMovement, [appearance(attribs(normal,red,default))]), entitySequentialMovement(init,EID,[right,left,up,up,down,down],[]).

Destacar que el enemigo es mortal y active para que est activo en todo momento segn el comportamiento definido por la regla entitySequentialMovement.

gunBasic: controla el comportamiento de una pistola que puede ser conseguida y disparada. Se trata de un comportamiento asociado al uso de objetos. Incluye la regla gunBasic/5 que permite definir una pistola, su municin, las entidades a las que puede disparar y qu pasa cuando se acabe dicha municin. Tendremos un objeto pistola creado mediante la regla createGameEntity/8, al que habr que asociarle la regla siguiente:

gunBasic(init,OID,AMMO,AIMLIST,AMMO_END)
OID: Identificador del objeto que ser controlado. AMMO: Nmero de disparos posibles a realizar. AIMLIST: Lista de entidades a las que puede disparar la pistola. AMMO_END: Que sucede con la pistola cuando se acaba la municin (destroy se destruye; keep se mantiene). Ejemplo de uso: Queremos crear una pistola (en la posicin 6,5 y representada con el carcter '' en negrita y con color cyan), con municin de 1 solo disparo, que slo sea capaz de matar enemigos 'E' y que desparecer (se destruir automticamente) una vez disparada. Para ello definimos dicho objeto pistola a travs de la regla createGameEntity/8 y su comportamiento a travs de la regla de uso gunBasic/5.
createGameEntity(OID,'',object,6,5,inactive,norule, [name(pistola),solid(false),static(false),use_rule(gunBasic), description('Derringer'),appearance(bold,cyan,default)]), gunBasic(init,OID,1,['E'],destroy).

Destacar que el objeto 'pistola' es not_solid (se puede atravesar), not_static (se puede coger) e inactive puesto que no tiene una regla de control asociada, solamente una de uso que es gunBasic.

launchBall: controla el comportamiento de una pelota que puede ser cogida y lanzada. Esta pelota se destruir al entrar en contacto con un elemento slido. Tambin puede darse que cualquier entidad mvil consiga la pelota con slo tocarla. Incluye una subregla para crear pelotas nuevas y situarlas en el campo cuando sea necesario, es decir, cuando hayan sido usadas o hayan desaparecido (launchBall(autoBallCreator,...)). Incluye la regla launchBall/3 que permite definir una pelota junto con su comportamiento. Tendremos dicho objeto pelota creado mediante la regla createGameEntity/8, al que habr que asociarle la regla siguiente: - 19 -

launchBall(init,OID_B,L_PARAMS)
OID_B: Identificador del objeto pelota. L_PARAMS: Lista de parmetros que permiten modificar el comportamiento estndar. (An no hay parmetros definidos. Se reservan para futuras ampliaciones) La creacin de pelotas nuevas cuando sean necesarias se realiza mediante la subregla launchBall(autoBallCreator,...)):

launchBall(autoBallCreator,SIMULBALLS,MAXBALLS,X,Y)
SIMULBALLS: Nmero de pelotas que puedes estar en el campo simultneamente. MAXBALLS: Nmero mximo de pelotas nuevas a crear. X,Y: Coordenadas del mapa dnde se crean las pelotas nuevas (pueden ser posiciones aleatorias). Ejemplo de uso: Queremos crear una pelota (en la posicin 6,5 y representada con el carcter 'o' en negrita y con color azul) que puede ser cogida y lanzada. Para ello definimos dicho objeto pelota a travs de la regla createGameEntity/8 y su comportamiento a travs de la regla launchBall/3.
createGameEntity(OID_B,'o',object,6,5,inactive,launchBall, [name(pistola),solid(false),static(false),use_rule(launchBall), description('Bolaparaserlanzada'),appearance(bold,cyan,default)]), launchBall(init,OID_B,[]).

Queremos crear tambin un creador automtico de pelotas que supervisar constantemente el nmero de pelotas activas presentes en el campo. Cada vez que dicho nmero sea < 1 crear una nueva pelota. Como mximo crear 10 pelotas nuevas, y todas ellas se situarn en la posicin 5,5.
launchBall(autoBallCreator,1,10,5,5).

Destacar que el objeto pelota es not_solid (se puede atravesar), not_static (se puede coger) e inactive puesto que si no la bola empezara a moverse antes de ser lanzada. Tambin hacer notar el hecho de que la regla launchBall se asocia tanto como regla de comportamiento como de uso, para tener en cuenta ambos sentidos: cuando pacman la use, la pelota debe moverse y desaparecer cuando entre en contacto con un elemento slido.

mineExplosion: crea un objeto que representa una mina que destruye todo lo que se encuentra dentro de su onda expansiva. Se trata de un comportamiento asociado a la accin de dejar un objeto. Incluye el sub-comportamiento explosion. Incluye la regla mine/5 que permite definir una mina, los ciclos de ejecucin que deben transcurrir para que explote desde que se produce la accin de dejarla en un lugar del mapa, el tamao de la onda expansiva (en caracteres) y algunos parmetros de su comportamiento. Tendremos un objeto mina creado mediante la regla createGameEntity/8, al que habr que asociarle la regla siguiente:

mine(init,OID,TIME,WAVE,L_PARAMS)
OID: Identificador del objeto mina. TIME: Nmero de ciclos de ejecucin que transcurren desde que pacman deja la mina hasta que explota. WAVE: Tamao de la onda expansiva (en caracteres). Por ejemplo, si el valor de WAVE es 2 quiere decir que destruir todo lo que haya en un radio de 3 caracteres - 20 -

alrededor de ella (incluyndola). Por tanto, si su posicin es (4,4) desaparecer todo lo existente desde (3,3) hasta (5,5). L_PARAMS: Parmetros para controlar la forma en que se comporta la mina.

no_destroy(L_EX): Permite definir una lista de objetos o entidades que sobrevivirn a la explosin de la mina.

Ejemplo de uso: Queremos crear una mina (en la posicin 5,2 y representada con el carcter ' +' en negrita y con color cyan), que explotar cuando hayan transcurrido 2 ciclos de ejecucin despus de dejarla, y destruir todo lo que encuentre a su alrededor hasta 1 celda de distancia excepto los cocos. Para ello definimos dicho objeto pistola a travs de la regla createGameEntity/8 y su comportamiento a travs de la regla mine/5.
createGameEntity(OID_MINE,'+',object,6,5,active,mine, [name(mina),solid(false),static(false),use_rule(norule), description('Minaprogramada'),appearance(bold,cyan,default)]), mine(init,OID_MINE,2,1,[no_destroy(['.'])]).

Destacar que el objeto 'mina' es not_solid (se puede atravesar), not_static (se puede coger), active puesto que tiene la regla de control mine asociada, y el parametro use_rule(norule) puesto que no tiene una regla de uso asociada.

pushBlocks: controla el comportamiento de un conjunto de bloques que pueden ser empujados mediante una palanca. Se trata de un comportamiento asociado al uso de objetos. Incluye la regla pushBlocks/3 que permite definir el objeto que se usar para empujar los bloques (palanca) y la lista de objetos bloque que pueden ser empujados. Tendremos el objeto palanca y tantos objetos objetos bloque como queramos creados mediante la regla createGameEntity/8. Al objeto palanca habr que asociarle la regla siguiente:

pushBlocks(init,OID,BLOCKLIST)
OID: Identificador del objeto usado para empujar bloques. BLOCKLIST: Lista de identificadores de objetos bloque que pueden ser empujados. Ejemplo de uso: Queremos crear un objeto palanca (en la posicin 5,6 y representado con el carcter '\\', (al ser un carcter conflictivo por eso lo representamos as), en color negro y fondo verde) que servir para empujar 2 objetos bloque (OID_B1 en la posicin 18,5 y OID_B2 en la posicin 18,6, representados por el carcter '%' en color azul). Para ello definimos los 3 objetos a travs de la regla createGameEntity/8 y el comportamiento de la palanca a travs de la regla de uso pushBlocks/3.
createGameEntity(OID_P,'\\',object,5,6,inactive,norule, [name(palanca),solid(false),static(false),use_rule(pushBlocks), description('Barragrandeconlaquesepuedenempujargrandesbloques'), appearance(normal,black,green)]), createGameEntity(OID_B1,'%',object,18,5,inactive,norule, [name(bloque1),solid(false),static(true),use_rule(norule), description('Bloquegrandedehormign'), appearance(normal,cyan,default)]), createGameEntity(OID_B2,'%',object,18,6,inactive,norule,

- 21 -

[name(bloque2),solid(false),static(true),use_rule(norule),

description('Bloquegrandedehormign'), appearance(normal,cyan,default)]), pushBlocks(init,OID_P,[OID_B1,OID_B2]).

Destacar que el objeto palanca es not_solid (se puede atravesar) y not_static (se puede coger), mientras que los objetos bloque son not_solid pero static (no se pueden coger, de forma que as slo puedan moverse de su posicin mediante el uso de la palanca). Otro detalle: todos ellos son inactive puesto que no tiene una regla de control asociada, solamente una de uso que es pushBlocks/3 asociada al objeto palanca.

quantumJump: implementa el comportamiento de un salto cuntico que permite al jugador saltar ms all de 1 celda en un paso simple. Incluye la regla quantumJump/4 que permite definir el objeto que realizar el salto cuntico, el nmero de celdas que puede saltar en un paso y una lista de parmetros que permiten controlar el comportamiento del salto. Tendremos el objeto que podr realizar el salto creado mediante la regla createGameEntity/8. Al objeto salto habr que asociarle la regla siguiente:

quantumJump(init,OID,STEP,LPARAMS)
OID: Identificador del objeto que realizar el salto cuntico. STEP: Nmero de celdas que puede saltar en un paso simple. LPARAMS: Lista de parmetros que controlan el comportamiento del salto. Ejemplo de uso: Queremos crear un objeto que realice saltos cunticos de 2 celdas (en la posicin 5,2 y representado con el carcter 'j'). Para ello definimos el objeto a travs de la regla createGameEntity/8 y el comportamiento para ejecutar los saltos con la regla quantumJump/4.
createGameEntity(OID_JUMP,'j',object,5,2,active,quantumJump, [name(quantum_jump),solid(false),static(false),use_rule(norule), description('QuantumJump')]), quantumJump(init,OID_JUMP,2,[]).

Destacar que el objeto 'quantum_jump' es not_solid (se puede atravesar), not_static (se puede coger), active puesto que tiene la regla de control quantumJump asociada, y el parmetro use_rule(norule) puesto que no tiene una regla de uso asociada.

respawnPoint: controla el comportamiento de un grupo de entidades que representan puntos de generacin para entidades nuevas (normalmente enemigos). Incluye la regla respawnPoint/6 que permite definir una lista de objetos que representan puntos o posiciones de generacin de entidades en el mapa, y que actan en grupo. Tendremos tantos objetos como puntos de generacin queramos creados mediante la regla createGameEntity/8. A cada grupo de puntos habr que asociarle la regla siguiente:

respawnPoint(init,L_OIDs,MAX_OBJS,L_OBJPROPS,L_INIT, L_MODIFIERS)
L_OIDs: Lista de identificadores de los objetos que representan puntos diferentes de generacin que actan formando un grupo. MAX_OBJS: Nmero mximo de objetos a regenerar. Una vez que se ha creado este - 22 -

nmero de objetos, el regenerador espera a que al menos uno de ellos sea destruido para continuar generando. L_OBJPROPS: Lista de propiedades de los objetos nuevos que se crean. Incluyen: - app(AP): Apariencia de las entidades nuevas que se generan. Por ej. 'E' - type(T): Tipo de las entidades nuevas que se generan. Por ej. mortal - active(CR): Parmetros de actividad para los objetos nuevos generados. Por ej. active - crule(CR): Regla de control para los objetos nuevos generados. Por ej. norule - name(N): Nombre para las entidades nuevas generadas. Por ej. noname - solid(S): Estado slido para las entidades nuevas generadas. Por ej. false - static(S): Estado esttico para las entidades nuevas generadas. Por ej. false - use_rule(R): Regla de uso para las entidades nuevas generadas. Por ej. norule - description(D): Descripcin para las entidades nuevas generadas. Por ej. unknown - appearance(attribs(ATR,TC,BC)): Atributos de apariencia para las nuevas entidades generadas (ATTRIBUTE, TEXTCOLOR, BACKG_COLOR) L_INIT: Lista de reglas que se invocan cuando se inicializa cada objeto nuevo generado. El primer elemento de dicha lista DEBE ser una variable sin instanciar que se instanciar con el identificador de la entidad (EID) del objeto nuevo que se genere. L_MODIFIERS: Lista de tomos que expresan modificaciones al comportamiento estndar. - probRespawn(PR): Probabilidad (1-1000) de generar una entidad nueva en cada ciclo de ejecucin. Por ej. 350 Ejemplo de uso: Queremos crear 2 puntos de generacin de hasta 5 entidades (como mximo) en las posiciones 5,2 y 10,2. Al generarse, dichas entidades sern mortales, estarn representadas con el carcter 'F', en negrita y color rojo, y se movern siempre de izquierda a derecha hasta encontrar una pared '#' usando el comportamiento enemyBasicMovement. Para ello definimos los 2 objetos puntos de generacin a travs de la regla createGameEntity/8 y los agrupamos a travs de la regla respawnPoint/6.
createGameEntity(OID_RS1,'',object,5,2,inactive,norule, [name(generador1),solid(false),static(true),use_rule(norule), description('Puntodegeneracin'),appearance(bold,red,default)]), createGameEntity(OID_RS2,'',object,10,2,inactive,norule, [name(generador2),solid(false),static(true),use_rule(norule), description('Puntodegeneracin'),appearance(bold,red,default)]), respawnPoint(init,[OID_RS1,OID_RS2],5, [app('F'),type(mortal),crule(enemyBasicMovement)],

- 23 -

[EID,enemyBasicMovement(init,EID,leftright,['#'])], []).

Destacar que los 2 objetos generadores son not_solid (se pueden atravesar), static (no se pueden coger) e inactive puesto que son posiciones fijas en el mapa. Tambin hacer notar el hecho de que el valor de los 2 parmetros que representan la regla de comportamiento y la de uso tienen valor norule, puesto que dichos puntos en s no tienen comportamiento ni se pueden usar. Ello es porque realmente son las entidades generadas las que tienen un comportamiento, establecido por la regla respawnPoint y que en este caso viene definido por la regla enemyBasicMovement. Tambin recordar que ser necesario cargar los ficheros correspondientes a los comportamientos que se combinen mediante la regla load_behaviour.

soccerGoal: controla el comportamiento de una portera de ftbol donde el usuario puede marcar goles lanzando pelotas. Crea un marcador para cada portera, y dicho marcador identifica a la portera de forma nica. Incluye la regla soccerGoal/6 que permite definir una portera junto con su marcador asociado, los objetos que se usarn para representar la portera, las posibles representaciones para la pelota, el nmero mximo de goles a anotar para que la portera se destruya. Tendremos los objetos portera (marcador), pelota, y los usados para formar la portera creados mediante la regla createGameEntity/8. Al objeto marcador habr que asociarle la regla siguiente:

soccerGoal(init,OID_SB,MAXGOALS,L_BALLAP,L_GOALOIDS, L_PARAMS)
OID_SB: Identificador del objeto considerado como marcador. MAXGOALS: Nmero de goles a anotar necesarios para que el partido se acabe (el mximo es 9). L_BALLAP: Lista con las apariencias posibles para la pelota. L_GOALOIDS: Lista con los identificadores de los objetos que forman parte de la portera. L_PARAMS: Lista de parmetros que modifican el comportamiento estndar de la portera. Ejemplo de uso: Queremos crear una portera con 2 objetos actuando como red de la misma, en las posiciones 9,1 y 9,2 y representadas con el carcter '|' en negrita y color azul, y un marcador que se ubicar en la posicin 0,2 y estar representado con el carcter '0', en negrita y color azul. Si se marcan 3 goles en dicha portera, los 2 objetos que representan la red de la misma desaparecern. Las pelotas que se lanzarn estarn representadas por el carcter 'o'. Para definir dicha portera creamos los objetos correspondientes al marcador y a la red (2) a travs de la regla createGameEntity/8 y su comportamiento a travs de la regla soccerGoal/6.
createGameEntity(OID_S,'0',object,0,2,active,soccerGoal, [name(marcador),solid(true),static(true),use_rule(norule), description('Marcador'),appearance(bold,cyan,default)]), createGameEntity(OID_G1,'|',object,9,1,inactive,norule, [name(porteria),solid(true),static(true),use_rule(norule), description('Reddelaportera'),appearance(bold,cyan,default)]), createGameEntity(OID_G2,'|',object,9,2,inactive,norule,

- 24 -

[name(porteria),solid(true),static(true),use_rule(norule), description('Reddelaportera'),appearance(bold,cyan,default)]), soccerGoal(init,OID_S,3,['o'],[OID_G1,OID_G2],[]).

Destacar que el objeto marcador es solid (no se puede atravesar), static (no se puede coger) y active para reflejar el resultado de goles anotados en todo momento, y los 2 objetos red son solid (no se pueden atravesar), static (no se pueden coger) e inactive puesto que son fijos en el mapa. Tambin hacer notar el hecho de que el objeto marcador es el nico que tiene asociada la regla de comportamiento soccerGoal, no los objetos red.

spiderGhost: controla el comportamiento de un fantasma que se mueve de pared a pared y que a veces ve y persigue al jugador (pacman). Incluye la regla spiderGhost/4 que permite definir un fantasma que puede perseguir a pacman con una probabilidad definida cuando entre en su ngulo de visin. Tendremos la entidad spiderGhost creada mediante la regla createGameEntity/8, y le asociaremos la regla siguiente:

spiderGhost(init,EID,L_LIMITS,L_PARAMS)
EID: Identificador de la entidad que ser controlada. L_LIMITS: Lista de los caracteres delimitadores que hacen que spiderGhost cambie su direccin de movimiento. L_PARAMS: Lista de modificadores del comportamiento de spiderGhost: - probFollowPacman: Probabilidad de perseguir a pacman cuando entre en su ngulo de visin (0-100). El valor por defecto es 50. - maxFollowTimes: Nmero mximo de cambios de direccin que har spiderGhost cuando persiga a pacman. El valor por defecto es 1. - av_dirs(LM): Lista de direcciones disponibles para ver y perseguir a pacman. El valor por defecto es [up,down,left,right] . Ejemplo de uso: Queremos crear un enemigo que se comportar como un spiderGhost en la posicin 11,1 y representado por el carcter 'F' de color rojo. Este fantasma perseguir a pacman cuando le vea con hasta 2 cambios de direccin posibles cada vez que salga de una pared, con un 80% de probabilidad.
createGameEntity(EID,'F',mortal,11,1,active,spiderGhost, [appearance(attribs(normal,red,default))]), spiderGhost(init,EID,['#'],[probFollowPacman(80),maxFollowTimes(2)]).

Destacar que el enemigo es mortal y active para que est activo en todo momento segn el comportamiento definido por la regla spiderGhost.

- 25 -

5.Definiendo comportamientos propios para entidades y objetos


Si has llegado hasta aqu, Enhorabuena! Si ests leyendo estas palabras ya sabes cmo crear un mapa e incluso puedes tener ya uno propio definido con objetos, entidades, paredes, cocos, etc. Por supuesto, estars deseando rizar el rizo con tu mapa. A partir de aqu la tarea de diseo pura y dura ya se acaba. Ahora toca crujir los nudillos, estirar la columna, concentrarse y darle caa a la programacin en Prolog. Cmo ya habrs visto en las explicaciones anteriores, los comportamientos son reglas implementadas en cdigo Prolog. En esta seccin te explicar cmo hacer los tuyos propios. Bien, s, lo s, tranquil@, vamos por partes como Jack el Destripador. Sabes programar en Prolog y ya tienes una idea bastante clara de cmo funciona pl-man pero, an as, te asaltan las dudas. Cmo hago para que una entidad se mueva? Cmo lo hago para que vean su entorno? Qu tengo que poner en el cdigo de la regla de uso de un objeto? En los siguientes prrafos voy a tratar de resolver todas estas preguntas y alguna ms con ejemplos de cdigo y explicando en detalle las reglas que hay implementadas en pl-man para hacer estas cosas y otras. Para empezar, necesitas saber lo bsico. Lo bsico es saber cmo decirle al entorno que tu entidad (objeto o enemigo, por ejemplo) quiere realizar una accin. En primer lugar, debes saber las acciones que puede realizar tu entidad:

moverse: Slo puedes moverte en las 4 direcciones bsicas (arriba, abajo, izquierda y derecha). coger y dejar objetos: A la hora de coger un objeto, el objeto debe estar en una casilla contigua a la posicin de tu entidad, ya que hay que especificar en qu direccin quieres coger el objeto (arriba, abajo, izquierda, derecha). usar objetos: Al igual que coger y dejar, usar un objeto debe realizarse en una direccin (arriba, abajo, izquierda o derecha). Por ejemplo, si quieres usar una llave para abrir una puerta, y la puerta est en la casilla justo a la derecha de tu entidad, tendras que usar la llave hacia la derecha.

Bien, ya tienes una idea de qu puede hacer tu entidad. Ahora slo necesitas saber cmo puede hacerlo. Es fcil. El juego, en su bucle principal, busca todos los hechos del predicado d_doAction/2 que encuentre en su base de conocimientos. Cada uno de estos hechos representa una accin a realizar por una entidad concreta del juego. Para cada predicado de estos que el juego encuentre, se encarga de lanzar las reglas necesarias para que la accin sea realizada. Los hechos del predicado d_doAction/2 se generan fcilmente lanzando la regla predefinida d_doAction/2. Sabiendo esto, es muy fcil que nuestro personaje realice acciones. Slo tenemos que lanzar doAction(_EID,_Action), sustituyendo _EID con el identificador de nuestra entidad y _Action con la accin que queremos que nuestra entidad realice. Nuestra entidad realizar esta accin en el siguiente turno de proceso. Slo nos falta saber un detalle. Qu hay que poner en _Actionpara que se realice la accin que nosotros queremos? Ah va :)...

moverse: move(right), move(left), move(up), move(down). coger objeto: get(right), get(left), get(up), get(down). dejar objeto: drop(right), drop(left), drop(up), drop(down). usar objeto: use(right), use(left), use(up), use(down). - 26 -

Bien, ya estamos listos para nuestra primera regla para mover una entidad (un fantasma, por ejemplo) de forma aleatoria por el mapa. El cdigo sera el siguiente: randomGhostControlRule(EID): Xisrandom(4), ( (X=0,A=up);(X=1,A=down); (X=2,A=left);(X=3,A=right) doAction(EID,move(A)). Figura 3. Regla que mueve un fantasma de forma aleatoria. Este tipo de regla es una regla de control o ControlRule. Estas reglas pueden ser asociadas a una entidad cuando esta es creada y son llamadas 1 vez en cada ciclo de ejecucin si la entidad est en estado activo (active). El motor de pl-man se encarga de lanzar esta regla, poniendo como parmetro el EID de la entidad a la que debe aplicarse, ya que varias entidades pueden utilizar la misma regla de control. ),

5.1. Sensores y otras yerbas


Hasta aqu, muy bien. Ahora podemos hacer que nuestras entidades se muevan por el mundo. Sin embargo, tenemos un problema. Cmo pueden nuestras entidades saber dnde estn o qu estn viendo para tomar una decisin en consecuencia? Para solventar este problema, el entorno de plman proporciona a nuestras entidades 2 tipos de sensores de visin. La siguiente figura muestra el comportamiento de estos dos sensores.

Sensor normal

Sensor de lista

Figura 4. Comparacin de funcionamiento de los sensores El primer sensor, el normal, nos permite ver el contenido de cualquiera de las 8 celdas que tenemos ahora mismo a nuestro alrededor. El segundo sensor, el de lista, nos proporciona una lista con todo lo que se puede ver hasta el primer objeto slido que nos impide ver ms all. De esta forma, en el ejemplo de la Figura 4, si le decimos que nos muestre lo que se ve hacia arriba nos devolvera la lista ['.','F','#'], mientras que si le preguntamos qu se ve a la derecha nos devolvera la lista ['#']. En ambos casos, nos muestra todo lo que podemos ver desde nuestra posicin. En el segundo caso, como a nuestra derecha hay una pared, no podemos ver ms all. - 27 -

Ambos sensores funcionan para cualquier entidad, tanto para pacman como para un fantasma o un objeto. La forma de utilizarlos es muy sencilla. Para poder saber que estamos viendo en cualquier momento utilizaremos el predicado see/3. Este predicado recibe como primer parmetro el tipo de sensor que queremos utilizar (normal o list), como 2 parmetro hacia dnde queremos mirar, incluyendo la posicin actual y las diagonales en el caso de sensor normal (here,up, down, left,right,leftdown,leftup,rightdown,rightup) y (up, downleft, o right) en el caso de sensor de tipo lista, y unifica el 3er parmetro con lo que estamos viendo exactamente. Nota: las diagonales se pueden expresar de las 2 formas posibles, por ejemplo, downleft leftdown. En la Figura 5 puedes ver las respuestas que da Prolog con varios ejemplos en el caso de la Figura 4. En caso de que queramos utilizar la regla see para una entidad creada de nuestro mapa, deberemos utilizar see/4. see/4 funciona exactamente igual que see/3, con la nica diferencia de que nos permite indicar cul es la entidad que queremos que mire. Esto se especifica poniendo como primer parmetro el EID de la entidad que debe mirar. El resto de parmetros son los mismos que en see/3. Utilizando estos sensores se pueden hacer comportamientos ms elaborados, ya que gracias a ellos podemos ver el entorno que nos rodea. Por ejemplo, podemos hacer fantasmas que sigan los pasillos y busquen a Pacman, o podemos hacer paredes que reaccionen y se aparten cuando vean un fantasma, o bombas que exploten cuando vean a alguien pasar. Una recomendacin al respecto: No se debe abusar del uso de los sensores de lista. Los sensores de lista escanean el mapa para obtener lo que se est viendo cada vez que son llamados. Esto lleva una carga de proceso que debe ser considerada para evitar sobrecargar el procesador. Hay que procurar usar cada sensor para lo que le corresponde, sin abusar :).
?see(normal,up,X). X='.' ?see(normal,right,X). X='#' ?see(normal,left,'.'). No ?see(normal,down,''). Yes ?see(normal,downleft,X). X='#' ?see(normal,rightup,'.'). Yes ?see(list,up,X). X=['.','F','#'] ?see(list,right,['#']). Yes ?see(list,left,['']). No ?see(list,down,X). X=['','.','#']

Figura 5. Respuestas de Prolog al objetivo see/3. A continuacin, en la Figura 6, puedes ver un ejemplo de regla que permite a una pared moverse arriba y abajo entre 2 muros, de forma muy sencilla, utilizando el sensor normal. % Mueve un muro arriba y abajo entre otros dos % % % Este es el aspecto que tendra ==> # # # => # => # # # # #

- 28 -

wallUpAndDownRule(EID):see(EID, normal, up, '#'), doAction(EID, move(down)). wallUpAndDownRule(EID):see(EID, normal, down, '#'), doAction(EID, move(up)). Figura 6. Cdigo para hacer una pared que se mueve arriba y abajo. Otro ejemplo sera un fantasma que custodia una puerta. Este fantasma se mantiene una fila por delante de la puerta y se mueve a izquierda o derecha slo cuando ve a pacman en uno u otro lado. La figura 7 muestra cmo hacer esto. % Fantasma que custodia una puerta % % % % seedir(left). seedir(right). guardianGhost(EID):seedir(DIR), see(EID, list, DIR, SEELIST), member('@', SEELIST), doAction(EID, move(DIR)), !. guardianGhost(_). % o derecha slo cuando ve a alguien #.#.#######.#.# # F # #######-####### El fantasma de la situacin de la derecha se mueve a izquierda

5.2. Marchando una de memoria


Ya podemos mover a nuestras entidades y hacerlas reaccionar ante lo que estn viendo en el entorno. Sin embargo, tenemos otro problema. Nuestras entidades no tienen forma de recordar nada, ni siquiera, qu es lo que estn haciendo ahora mismo. Esto es un problema, ya que no podemos hacer que una entidad tenga una planificacin sencilla del tipo Tomo una direccin fija aleatoria hasta la siguiente pared y all repito. Para poder implementar de forma sencilla una memoria a nuestras entidades, lo haremos como siempre lo hemos hecho en Prolog: Utilizando predicados dinmicos. El archivo que define un mapa es cdigo Prolog puro, por lo que nadie nos impide declararnos un predicado dinmico como queramos y utilizarlo. Si necesitamos inicializar los hechos de nuestro predicado dinmico, podemos hacerlo en la regla initMap/0, para asegurarnos que nuestro mapa funcionar siempre bien.

- 29 -

Volviendo al ejemplo de la pared que se mova arriba y abajo, podemos implementar otra pared que se mueva arriba y abajo pero en un espacio ms amplio. Para eso, nuestra pared deber saber en todo momento hacia qu direccin se est moviendo. La figura 8 muestra un ejemplo de cmo hacer esto en Prolog. % Mueve un muro arriba y abajo entre otros dos % :- dynamic d_wallActualDirection/1. initMap:.............................. % Poner la direccin inicial del muro retractall(d_wallActualDirection(_)), assert(d_wallActualDirection(up)). % direction(D1, D2): D1 es direccin actual, D2 es la siguiente direction(up, down). direction(down, up). wallUpAndDownRuleExtended(EID):direction(DIR_NOW, DIR_NEXT), see(EID, normal, DIR_NOW, '#'), retractall(d_wallActualDirection(_)), assert(d_wallActualDirection(DIR_NEXT)), doAction(EID, move(DIR_NEXT)), !. wallUpAndDownRuleExtended(EID):d_wallActualDirection(DIR_NOW), doAction(EID, move(DIR_NOW)). Figura 8. Una pared que sube y baja hasta que se encuentra con otra pared. La memoria es indispensable para hacer determinadas tareas y, en general, es muy probable que acabes usndola para casi todo. Otro ejemplo de cosas que podemos hacer utilizando predicados dinmicos podra ser el siguiente: Tener una pared que tapa un pasadizo secreto, y hacer que la pared se aparte sola la 3 vez que el pacman pase por delante de ella. La Figura 9 muestra cmo hacerlo. % Pared que se aparta sola la 3 vez que % Pacman pase por delante de ella % % - 30 # @ # ########### #.... ....# ##### #####

:- dynamic d_timesToOpenWall/2. :- dynamic d_wallMovements/1. initMap:.............................. % Inicialmente, quedan 3 veces para abrir la pared % Y cuando se abra, tendr que moverse 2 casillas retractall(d_timesToOpenWall(_,_)), retractall(d_wallMovements(_)), assert(d_wallMovements(2)), assert(d_timesToOpenWall(3, not_seeing_pacman)). % Si la puerta ya est abierta, no hacer nada autoOpenSecretWall(EID):d_wallMovements(0), !. % Si ya ha pasado N veces y la puerta an no se ha abierto, abrir autoOpenSecretWall(EID):d_timesToOpenWall(0, _), d_wallMovements(M), M > 0, M1 is M-1, retractall(d_wallMovements(_)), assert(d_wallMovements(M1)), doAction(move(down)), !. % Cada vez que vea al comecocos aparecer, lo que significa que % en el instante anterior no lo estaba viendo, resto uno a las % veces que quedan para abrir la puerta. autoOpenSecretWall(EID):see(EID, normal, up, '@'), d_timesToOpenWall(T, not_seeing_pacman)), T > 0, retractall(d_timesToOpenWall(_,_)), T1 is T - 1, assert(d_timesToOpenWall(T1, seeing_pacman)), !.

- 31 -

% Cada vez que dejo de ver al comecocos (en el instante anterior % estaba vindolo y ahora no), anoto que ya no estoy vindolo. autoOpenSecretWall(EID):see(EID, normal, up, SEE), SEE \= '@', d_timesToOpenWall(T, seeing_pacman), retractall(d_timesToOpenWall(_,_)), assert(d_timesToOpenWall(T, not_seeing_pacman)). Figura 9. Puerta secreta que se abre la 3 vez que pacman pasa por delante.

5.3. Entidades en tiempo real, Al vuelo!


Una ltima cosa que seguramente echars de menos es la posibilidad de crear y destruir entidades y objetos en tiempo real, durante el desarrollo de la partida. Esta posibilidad es esencial si quieres implementar objetos como una pistola o enemigos como un lanzamisiles automtico. Crear y destruir entidades es muy simple. Ya has aprendido anteriormente a crear entidades con el objetivo createGameEntity/8. createGameEntity/8 puede ser utilizado en cualquier momento, no necesariamente dentro de initMap. Esto significa que cualquier regla de control de cualquier objeto o entidad puede llamar a createGameEntity/8 y dar lugar a la creacin de una nueva entidad. Por otra parte, dispones de otro objetivo implementado en pl-man que te permite destruir entidades: el predicado destroyGameEntity/1. A destroyGameEntity/1 basta con que le pases el identificador de la entidad que quieres destruir y, automticamente, la entidad dejar de existir en el juego. La combinacin de las 2 anteriores podemos utilizarla para implementar un lanzamisiles automtico. El ejemplo del lanzamisiles automtico lo tienes en la figura 10. % Lanzamisiles automtico % % % #############@# #) > .....# #########.##### El lanzamisiles disparar un nuevo misil cada 8 turnos.

% Los misiles se movern slos hasta chocar con la pared, % momento en el que se destruirn % :-dynamic d_timesToLaunchMissile/2. initMap:.............................. retractall(d_timesToLaunchMissile(_,_)). - 32 -

% Comenzar cuenta atrs cuando no haya ninguna missileLauncherRule(EID):not(d_timesToLaunchMissile(EID, _)), assert(d_timesToLaunchMissile(EID, 8)), !. % Lanzar misil cuando acabe la cuenta atrs missileLauncherRule(EID):d_timesToLaunchMissile(EID, 0),
createGameEntity('>', mortal, 2, 1, active, missileRule, 0),

retract(d_timesToLaunchMissile(EID, 0)). % Continuar cuenta atrs para lanzamiento de misil missileLauncherRule(EID):d_timesToLaunchMissile(EID, T), T > 0, T1 is T - 1, retract(d_timesToLaunchMissile(EID, T)), assert(d_timesToLaunchMissile(EID, T1)), !. % Si el misil llega a la pared, se destruye missileRule(EID):see(EID, normal, right, '#'), destroyGameEntity(EID), !. % Mientras el misil no llegue a la pared, avanza missileRule(EID):doAction(EID, move(right)). Figura 10. Lanzamisiles automtico creando y destruyendo entidades.

- 33 -

6. Otros predicados interesantes de Pl-man


Si has llegado hasta aqu, ya sabes todo lo imprescindible para disear e implementar casi cualquier tipo de mapa que se te ocurra. Esta seccin es complementaria y explica otros predicados implementados en pl-man que te pueden ser de utilidad para realizar determinadas acciones sobre el entorno. Por supuesto, si encuentras que hay alguna cosa que te gustara implementar en un mapa de pl-man y no encuentras forma de hacerlo, no dudes en hacrmelo saber para que pueda ayudarte o implementar alguna nueva funcionalidad en el entorno. entityLocation(EID, X, Y, Ap) La entidad EID est en la posicin X, Y y tiene la Apariencia Ap. entityType(EID, Type) La entidad EID es del tipo Type. solidEntity(EID) La entidad EID es slida staticObject(EID) EID es el identificador de un objeto que es esttico. objectName(ObjID, Name) ObjID es el identificador de un objeto que tiene por nombre Name. changeEntityAppearance(EID, NewAp, OldAp) La entidad EID que antes tena una apariencia OldAp ahora tiene la apariencia NewAp changeEntityLocation(EID, NewX, NewY, OldX, OldY) La entidad EID que antes estaba en las coordenadas (OldX, OldY) ahora est en (NewX, NewY) deactivateEntity(EID) Desactiva la entidad EID (la entidad dejar de llamar a su regla de control, por lo que se quedar completamente quieta y no har nada hasta ser reactivada). activateEntity(EID) Activa la entidad EID, por lo que esta entidad comenzar a llamar de nuevo a su regla de control en cada ciclo de proceso. Ojo! No activar entidades que no tengan regla de control. changeObjectName(ObjID, NewName, OldName) Cambia el antiguo nombre del objeto (OldName) con identificador ObjID por un nuevo nombre NewName. makeObjectStatic(ObjID) Hace que un objeto ObjID sea esttico (no pueda ser cogido por nadie) makeObjectSolid(ObjID) Hace que el objeto ObjID sea slido (no pueda ser atravesado por nadie) makeObjectNotStatic(ObjID) Hace que el objeto ObjID deje de ser esttico (podr ser cogido por otras entidades)

- 34 -

makeObjectNotSolid(ObjID) Hace que el objeto ObjID deje de ser slido (podr ser atravesado por otras entidades).

- 35 -

También podría gustarte