Ya hemos conocido las herramientas de wme y hemos estudiado lo básico sobre la programación(scripting). Ahora es momento de ver como se aplica todo esto al diseño del juego. Antes de empezar vamos a explicar un poco los tipos de ficheros que utiliza wme(es estrictamente necesario usar este tipo de nomenclatura para los ficheros).
*.script → Son ficheros que contienen el código del programa.
*.inc → Son ficheros que se podrán incluir en los ficheros .script con la clausula #include.
Normalmente estos ficheros tienen cientos de lineas de código, que de otra forma tendríamos que escribir cada vez que las necesitáramos. El primer ejemplo de esto, es el fichero “data\scripts\base.inc”. Este fichero se incluye prácticamente en todos los scripts. El contenido de estos ficheros es el mismo que los .script, con la particularidad que podremos incluirlos en otros ficheros.
*.scene → Son ficheros que incluyen la información de las escenas definidas en el editor de escenas. Es posible crear este fichero a mano, pero es mas recomendable usar el editor de escenas, te facilitarás el trabajo.
*.sprite → son ficheros donde se almacena la información de los sprites, como vimos en el primer capitulo, los sprites eran por decirlo de algún modo, una especie de animaciones, que se creaban con el editor de sprites. También es posible crear estos ficheros a mano pero es más engorroso.
*.actor → Son ficheros donde se definen los actores, y las animaciones de estos.
*.entity → En estos ficheros se definen las entidades.
*.font → Son ficheros donde se definen las fuentes que vamos a usar en el juego, admite de dos tipos, tipo mapas de bits y tipos true type.
*.windows → Son ficheros donde se definen las interfaces del juego, por ejemplo: menús, paneles, etc.
*.image → Son ficheros que almacenan imágenes, con la capacidad de crear repetición(mosaicos), estos ficheros son muy útiles para inventarios.
*.button → Son ficheros que definen como son los botones, por ejemplo los botones de los menús.
Recomendación: Lo mejor es coger cada uno de estos archivos de la demo incluida en wme, e investigarlos, y exprimirlos, para aprender a conocerlos. Quizá cuando acabe con la traducción, haga unos tutoriales explicando mas a fondo estos ficheros.
Aparte de estos tipos de ficheros, wme presenta unos archivos especiales, a los que es posible cambiar sus nombres, pero estos son los nombres que se crean por defecto:
default.game y startup.setting → Son creados por el administrador de proyectos y almacenados en la carpeta principal del proyecto, en ellos se almacenan las características del juego, y las opciones iniciales.
String.tab → Se almacena también en la carpeta principal del proyecto, y contiene las tablas de cadenas de caracteres para los distintos idiomas. Por si queremos tener un juego en varios idiomas.
items.items → Contiene la declaración de los objetos del inventario que se usarán a lo largo del juego. Se almacena en la carpeta “data\items”.
responses.def → En este fichero se almacena como se ve la ventana de dialogo en las conversaciones de los personajes. Se almacena en “data\interface”.
inventory.def → En este fichero se define el aspecto de la caja del inventario de nuestros personajes. Se guarda en “data\interface”.
Como comente antes, os recomiendo que vayáis explorando estos ficheros, y os familiaricéis con ellos.
Pero dejemos esto de lado, y empecemos con la cosa mas simple – el ajuste de la escena. Si exploramos el contenido de alguna escena ya creada en el explorador del administrador de proyectos, veremos que todas las escenas contienen un fichero .scene, y una carpeta llamada scr que contiene un fichero llamado scene_init.script
Nota: en los ejemplos que vienen con wintermute hay mas ficheros, pero en esencia, una escena con lo mas básico tiene esos dos ficheros.
Bien pues internamente, wme lee el fichero de escena (.scene), y prepara todo tal y como esta definido en el fichero de escena, posteriormente carga todos los ficheros .scripts que participan en la escena, y automáticamente ejecuta el fichero llamado scene_init.script. Este fichero lo que hacer es ejecutar todas las acciones necesarias cuando se carga la escena, por ejemplo:
Si quieres que tu personaje al entrar a una escena que es muy oscura diga “oju! Que oscuro esta esto!”, pues esto deberemos definirlo en este fichero, así pues vamos a analizar y a comentar este fichero( scene_init.script ).
#include “scripts\base.inc” //Ahora definimos las opciones iniciales de la escena actor.SkipTo(733,562); // Posicionamos al actor en un punto de la escena actor.Direction=DI_DOWN;// Hacemos que el actor mire hacia una direccion actor.Active=true;// Hacemos el actor visible dentro de la escena //Ahora definimos el estado de la escena global StateWarehouse;//Creamos esta variable para almacenar el estado actual de la escena //Comprobamos el estado de la variable que hemos creado, si no tiene valor, se lo agregamos if(StateWarehouse==null) { StateWarehouse.Visited=false; /* Creamos un atributo para la variable de estado llamada Visited y le damos el valor falso, ya que aun no hemos visitado la escena */ } if(!stateWarehouse.Visited) // Si no hemos visitado la escena { StateWarehouse.Visited=true; /* Le damos el valor true a escena, si entramos en ella y nunca antes la habíamos visitado*/ //Esta es la primera entrada en la escena } //Aquí acaba el fichero scene_init.script
Quizás pienses que este script es una locura solo para comprobar si hemos visitado una escena o no, pero créeme, hay mas de lo que parece a simple vista. Este script que puede ofrecer muchas posibilidades, desde que el juego empieza, es necesario registrar las escenas que vamos visitando. Por ejemplo esas aventuras que cuando entras a una escena y explota un puente. El puente solo explota una vez, no cada vez que entremos, por eso es necesario y útil este script, y es recomendable entenderlo para poder diseñar aventuras bien construidas.
Bien cuando entendemos este script, en realidad lo que hace es algo muy simple.
Bueno como hay miles de métodos diferentes, he decidido coger el camino fácil y explicarlos conforme vayan saliendo.( palabras del creador original de la guía, con el tiempo quiero construir un pequeño manual de todos los métodos, atributos y eventos de los que nos provee wme).
Analicemos el script del ejemplo anterior linea por linea:
Ya sabemos que los objetos tienen sus métodos, que son llamados mediante:
nombre_objeto.nombre_metodo();
Nuestra linea a analizar es la siguiente:
actor.SkipTo(733, 562);
Pues bien, en esta linea llamamos al método skipTo() de nuestro objeto actor.
“actor” es una variable global de tipo Object que contiene a nuestro actor, y que es declarada en un script diferente. Ahora alguien se levantará y me dirá: he tu mentiroso, tu dijiste que había que definir cada variable global antes de usarla. Y yo le respondo, es verdad, esta ahí, pero no se ve, ya que va incluida en el fichero base.inc que incluimos en la primera linea. Veis la potencia del include? No tienes que declarar el actor en cada script, simplemente incluye este fichero al principio del script, y el programa se encargará del resto.
Bueno, volvamos a nuestro objeto actor y analicemos los métodos y atributos que hemos usado, y añadiremos dos mas realmente útiles:
Actor.SkipTo(x,y); → Establece al actor en una posición determinada de la pantalla. Asegúrese que esta posición esta dentro de la pantalla y ademas este dentro de una region activa.
actor.Direction= vista; → Es un atributo que establece la dirección hacia la que mira el actor, vista puede tener ocho valores posibles( DI_UP, DI_DOWN, DI_LEFT, DI_RIGHT, DI_UPRIGHT, DI_UPLEFT, DI_DOWNRIGHT, DI_DOWNLEFT )
actor.Active= true / false; → Este atributo es común a todos los nodos, hacen que estos estén activos o inactivos(visibles o invisibles).
actor.GoTo(x,y); → Este método hace que el actor camine a las coordenadas especificadas como parámetros.
actor.Talk(“texto”);→ el actor dice lo que se le pase por parámetro.
Nota: Recordad siempre que wme hace distinción entre mayúsculas y minúsculas.
Bien, lo mejor es probar estos métodos en la practica,trabajemos sobre nuestro scene_init.script, luego si abrimos el proyecto con el que estábamos trabajando, en el capítulo 1.3. Editor de Escenas, si lo recordábamos, hablábamos de este fichero, y además incluso lo modificamos, pues ahora lo veremos mas a fondo.
Bien, para abrir este archivo, debíamos ir a data–> scenes → warehouse(que es el nombre con el que la guardábamos)–>scr, aquí podemos localizar nuestro fichero scene_init.script. A partir de ahora, cuando hable de este fichero, deberías saber localizarlo fácilmente. Cada escena dispone de su fichero scene_init.script.
Abre este fichero haciendo doble clic sobre el, y localiza la linea que dice:
actor.Active = true;
y añade estas lineas tras ella:
actor.GoTo(365,561); actor.Direction = DI_DOWN; actor.Talk("¡Que bonito almacén");
Ahora deberíamos tener este resultado en el fichero scene_init.script:
#include “scriptsbase.inc” //ahora definimos las opciones iniciales de la escena actor.SkipTo(733,562); // posicionamos al actor en un punto de la escena actor.Direction=DI_DOWN;// hacemos que el actor mire hacia una dirección actor.Active=true;// hacemos el actor visible dentro de la escena actor.GoTo(365,561); actor.Direction = DI_DOWN; actor.Talk("¡Que bonito almacén!"); //ahora definimos el estado de la escena global StateWarehouse;//creamos esta variable para almacenar el estado actual de la escena //comprobamos el estado de la variable que hemos creado, si no tiene valor, se lo agregamos if(StateWarehouse==null) { StateWarehouse.Visited=false; /* creamos un atributo para la variable de estado llamada Visited y le damos el valor falso, ya que aun no hemos visitado la escena */ } if(!stateWarehouse.Visited) // si no hemos visitado la escena { StateWarehouse.Visited=true; /* le damos el valor true a escena, si entramos en ella, ya que nunca antes la habíamos visitado*/ //esta es la primera entrada en la escena }
Guarda el fichero y ejecuta el juego desde el administrador de proyectos. Antes de continuar, hablemos un poco de uno de los aspectos mas importantes a la hora de programar juegos en wme. Wme genera un fichero llamado wme.log y que guarda en la carpeta principal del proyecto. Este es un fichero donde se registran todos los errores que puedan tener los scripts, ademas de otras cosas.
Por ejemplo, si tienes un error en un script, el compilador mostrará un mensaje de error en la pantalla, pero en el fichero wme.log se genera una linea de error diciendo que script lo generó, y en que linea del script. Recomiendo que aprendas a controlar esto, porque te ahorrara muchísimo tiempo, date cuenta que si te dicen el archivo que genera el error y la linea en la que lo genera, solo tendrás que buscar esa linea, e investigar que paso.
Ok, sigamos adelante, si ejecutasteis el juego, al hacerlo pudisteis ver que nuestro personaje se situaba delante de las cajas, y decía la frase “¡Que bonito almacén!”, pues eso lo conseguimos con estas dos lineas:
actor.GoTo(365,561); // hace que el actor ande hacia las cajas actor.Talk("¡Que bonito almacen!"); //hace que el actor diga "¡Que bonito almacén!"
Bien hagamos algo para interactuar con la escena. Abre la escena warehouse en el editor de escenas, selecciona la entidad de región de la puerta, que habíamos creado en el capitulo 1.3, y presiona sobre el botón de scripts(1), y en la nueva ventana, pulsa sobre new script(2).
En la siguiente ventana, selecciona como plantilla(template) empty.script en la lista de la izquierda, y después presiona ok.
Este proceso crea un fichero vacío llamado door.script y lo almacena en el directorio scr de la escena a la que pertenezca, en este caso sera warehouse. Este archivo que hemos creado esta directamente relacionado con las puertas de nuestra escena, es decir, a partir de ahora podremos interactuar con este objeto gracias al script que hemos creado. Salva la escena.
Ahora vete a la carpeta scr de nuestra escena, y abre el fichero que acabamos de crear, dependerá del nombre que le disteis a la entidad en el capitulo 1.3 pero supongo que le pondríais de nombre puerta, o door, luego el fichero que hemos creado tendrá uno de esos nombres.
Bien, en ese archivo podremos ver lo siguiente:
#include "scripts\base.inc" //////////////////////////////////////////////////////////////////////////////// //on "event" //{ // ... //}
Como puedes ver, no tiene mucha funcionalidad. Simplemente aparece la clausula #include con nuestro viejo amigo el fichero base.inc, pero aparte de esto no dispone de ningún tipo de funcionalidad. Necesitamos añadir algo. Bien, lo que vamos a añadir es un evento.
Eventos
Antes de continuar, hagamos un pequeño inciso para explicar que son los eventos. Los eventos tal y como su palabra indica, son cosas que ocurren durante el juego, por ejemplo un click de ratón es un evento. Los eventos son muy útiles, ya que principalmente son la vía por la que el jugador se comunicara con el juego para que se realicen acciones.
Un ejemplo muy básico, cuando hacemos un click con el botón izquierdo del ratón sobre un punto de la pantalla, el personaje debería ir hasta ese punto, pues en Wme tenemos una serie de eventos predefinidos, de momento vamos a ver cinco eventos:
on “LeftClick” - Cuando pulsamos el botón izquierdo del ratón sobre algún nodo.
on "RightClick" - Cuando pulsamos el botón derecho del ratón sobre algún nodo.
on "MiddleClick"- Cuando pulsamos el botón central del ratón sobre algún nodo.
on "LeftDoubleClick" - doble clic del botón izquierdo del ratón sobre algún nodo.
on "RightDoubleClick" - doble clic del botón derecho del ratón sobre algún nodo.
Nota: un nodo es cada uno de los elementos en wme( entidades, regiones, objetos, actores,…)
Bien, ya hemos hablado un poco de los eventos, sigamos con el ejemplo donde lo habíamos dejado.
Abramos nuestro script de la puerta situado en la carpeta scr de nuestra escena.
Elimina del script las lineas:
//////////////////////////////////////////////////////////////////////////////// //on "event" //{ // ... //}
y agreguemos lo siguiente:
on "LeftClick" { actor.Talk("'¡He pulsado sobre la puerta!"); }
Si analizamos estas lineas, como ves lo que hacemos es crear un evento para cuando pulsemos el botón izquierdo del ratón sobre este objeto.
on “LeftClick” { actor.Talk("'¡he pulsado sobre la puerta!"); }
Y todo lo que se encuentra entre llaves, serán las lineas de código que se ejecutarán cuando hagamos un click con el botón izquierdo del ratón sobre este objeto, en este caso a puerta. Como ves, en este caso lo único que hacemos, es que el actor(nosotros) diga “¡he pulsado la puerta!”. Podemos poner cientos de lineas, pero eso ya dependerá de lo que nosotros necesitemos.
Es posible agregar mas de un evento en un mismo script.
Bueno si después de añadir esas lineas al script ejecutaste el juego, y hiciste un click con el botón izquierdo del ratón sobre las puertas, comprobarás que realmente funciona, y que cuando lo haces nuestro personaje nos dice: “He pulsado sobre la puerta”. Fantástico, verdad sigamos.
Otra particularidad que tiene el aplicar un script a un nodo, es que puedes modificar o consultar las propiedades de ese nodo mediante la palabra reservada this. Veamos un ejemplo:
Modifica la linea que creamos antes( actor.Talk("'¡he pulsado sobre la puerta!"); ) de la siguiente manera:
actor.Talk(this.Name);
Si guardas el script, y ejecutas el juego, si vuelves a realizar click sobre las puertas, ahora nuestro personaje dice Door. ¿ te suena? Claro, es el nombre que le habíamos puesto al objeto en el editor de escenas. Como puedes ver, lo que configuramos a través del editor de escenas, es fácilmente accesible desde los scripts. Por otro lado, la palabra this en esta linea, hace referencia al objeto actor.
Veamos otro método.
actor.GoToObject(Nodo) → Este método, hace que nuestro personaje ande hacia el nodo especificado como parámetro, y una vez allí, dirija la mirada en dirección al objeto. En este caso el nodo puede ser un objeto, una región, una entidad, ….
Pero como ya sabemos, podemos usar la palabra reservada this para referirnos a este nodo. Añadamos las siguientes lineas a nuestro script de la puerta delante de la linea “actor.Talk(this.Name);” :
actor.GoToObject(this);
Si establecimos bien las coordenadas de la puerta en el editor de escenas, y ejecutamos nuestro proyecto, veremos que al hacer clic izquierdo sobre la puerta, nuestro personaje se acercara a ella, y dirá el nombre que nosotros le indicamos en el editor de escenas cuando las creamos.
El último experimento que haremos, con nuestra puerta, será desactivar su atributo Active, deshabilitando así la puerta cuando realizamos click sobre ella. Para ello, debemos añadir la siguiente linea a nuestro script de la puerta:
this.Active = false;
Finalmente nuestro script de la puerta quedará de la siguiente manera:
on "LeftClick" { actor.GoToObject(this); // El actor va al objeto y mira en dirección a el. actor.Talk(this.Name); // El actor dice su nombre. this.Active = false; // La puerta queda desactivada. }
Bien, si lo guardamos y lo ejecutamos, al hacer click sobre la puerta, el personaje se acerca hacia ella, dice su nombre, y la puerta se desactiva, ya no podremos volver a hacer click más sobre ella, no se nos marcará, es como si hubiera desaparecido. Esta técnica es muy habitual en algunas aventuras, hay veces que cuando ya has examinado un objeto, ya no podemos hacer mas sobre él.
Como veis con imaginación se podrían hacer muchas cosas de manera muy simple, pero los script también se pueden complicar cuando es necesario controlar muchas cosas al mismo tiempo, y mas aun, cuando estas cosas puedan interactuar entre ellas. Pero mi consejo es siempre el mismo, practicad, investigad, y cuando no sepáis algo, preguntad.
Hasta el momento hemos trabajado con métodos de dos tipos de objetos, el objeto actor y el objeto entidad de región(entity region) que habíamos referenciado mediante la palabra reservada this. También hemos modificado el atributo active de la entidad de región( en este caso la puerta) a false, haciendo que se desactivara.
Volvamos a la imagen que veíamos al principio y miremos desde el punto de vista de un desarrollador, quizá ahora podamos entenderla mejor.
Ahora seguramente entiendas porque el objeto principal del juego se llama Game, como puedes ver en este gráfico, todo deriva del objeto Game, si queremos por ejemplo saber donde se encuentra nuestra entidad puerta dentro de este diagrama, veremos que la ruta es la siguiente:
Game → Scene → Door.
Esto es así ya que nuestra puerta, es una entidad de región.
Nota: La palabra entidad hace referencia a algo(objeto) que es perceptible, es decir que tiene una serie de características(atributos), y puede realizar una serie de acciones(métodos).
Bien, sabemos que podemos referenciar una escena como Scene. Esto se debe a que en el fichero game.script, es donde se le da a la variable scene el valor de la escena con la siguiente linea:
Scene = Game.Scene;
Scene es como wme define por defecto en el fichero base.inc a esta variable que servirá para hacer referencia a nuestra escena. Este nombre wme, lo designa mediante la linea:
global Scene;
Si cambiamos este nombre de variable en el fichero base.inc, y modificamos correctamente el fichero game.script, para hacer referencia a la escena, lo haríamos con el nuevo nombre que le hayamos indicado.
Recomendación: hasta que no se tenga soltura en la jerarquía de wme y se adquiera algo de experiencia con el scripting, no recomiendo modificar estas cosas, ya que puede ocasionar que nuestro juego deje de funcionar.
Luego por un lado tenemos el objeto Scene, y por otro el objeto Game, como se puede uno imaginar, el objeto Game servirá para controlar las operaciones del juego en general, y el objeto Scene servirá para controlar las operaciones dentro de una escena. Estudiemos un poco las funciones mas representativas de cada uno de estos objetos.
El primero, del objeto Game:
Game.ChangeScene(escena.scene) → Es una función que lo que hace es cambiar de escena, toma como argumento un fichero de tipo .scene.
El segundo, del objeto Scene:
Scene.GetNode(NodeName) → Es una función que devuelve el nodo cuyo nombre es el que le pasamos como parámetro.
Como vemos, una realiza una acción sobre el juego en general, y la otra realiza una acción sobre la escena en la que nos encontramos.
Bien, hagamos algo que demuestre el poder de wme. Vuelve a wme, y abre la escena(warehouse) con la que estamos trabajando en el editor de escenas. Lo primero, crearemos una región y la llamaremos salida. Posiciónate sobre la esquina inferior izquierda como en la siguiente imagen(deberías descubrir rápidamente que se trata de la zona roja). Fíjate también en la posición donde la situamos de la lista de nodos, ya que si la situamos por encima del suelo, quedaría escondido bajo el suelo, y no se podría pinchar durante el juego.
Ahora añadiremos un script a esta región, pulsando sobre el botón scrips, usa una plantilla empty.script y guarda la escena.
Antes de seguir, veamos dos eventos nuevos:
on “ActorEntry” → Este evento se produce cuando un actor entra en una región actual. A estas regiones las llamamos regiones trampa, ya que se produce un evento cuando el actor entra en una región.
On “ActorLeave” → Este evento se produce cuando el actor abandona la región.
Lo ultimo que necesitamos para este ejemplo, es un atributo, que servirá, para dejar libre el control del jugador, es decir, que no podamos controlar al personaje mientras esta realizando alguna acción.
Esto es necesario, ya que si no lo hacemos, y le indicamos al personaje que realice una acción, y antes de que la termine, le indicamos que realice otra, la primera no sera completada, y es muy probable que se produzcan errores. Por eso necesitamos conocer el atributo Interactive del objeto Game.
Game.Interactive= true / false;
Como ya hemos comentado esta funcionalidad, sirve para evitar que el jugador(nosotros) podamos realizar una acción, mientras el personaje esta realizando otra acción.
Si este atributo esta a true, podemos controlar a nuestro personaje, si por el contrario esta a false, no podremos realizar acciones. Y como dijimos es bastante importante para que nuestro juego no se nos quede pillado.
Pero recuerda, si en algún momento pones este atributo a false mientras el personaje realiza alguna acción,recuerda que después tendrás que volverlo a poner a true, ya que si no lo haces, no podremos controlar a nuestro personaje y los jugadores se pondrán furiosos.
Bien, intentemos combinar todas estas ideas, para montar algo mas complejo y estable.
Lo primero que haremos será ir al script de nuestra puerta, el que veníamos trabajando durante este capítulo.
Lo modificaremos y haremos que tenga este aspecto:
on “LeftClick” { Game.Interactive= false; // desactivamos el control del personaje actor.GoToObject(this); // el actor anda hasta la puerta this.Active= false; // desactivamos el objeto puerta actor.Talk(“Oh no. La puerta esta soldada”); // el actor dice una frase Game.Interactive=true; // devolvemos el control del personaje }
Ahora abrimos el salida.script que creamos anteriormente con la región de la esquina inferior izquierda, y añadiremos un nuevo evento. El fichero debería quedar así:
salida.script
#include "scripts\base.inc" on "ActorEntry" //evento de cuando el actor entre en la región salida { Game.Interactive = false; // desactivamos el control del personaje var puerta = Scene.GetNode("Door"); /*Guardamos el objeto Door(nombre que usamos en el editor de escenas) en la variable puerta */ if (puerta.Active) // si no hemos echo click en la puerta { actor.Talk("No volveré a mi piso hasta no estar segura de que no puedo entrar en el almacen"); } else // si hemos echo click en la puerta { actor.Talk("Vale, creo que no podre entrar en el almacén"); Game.ChangeScene("scenes\room\room.scene"); // cambiamos la escena } Game.Interactive = true; //devolvemos el control al jugador }
Bien, veamos que esta ocurriendo aquí. En nuestro guion de juego, tenemos apuntado que el personaje necesita entrar en el almacén, pero la puerta esta cerrada. De alguna manera nuestro personaje tiene que saber que la puerta esta cerrada para poder continuar con la aventura, por eso, en nuestro script estamos imponiendo que tenga que hacer click en la puerta, para que podamos cambiar de escena. Mientras no hagamos click en la puerta, nuestro personaje no podrá cambiar de escena.
Esto es debido, a que hemos impuesto en la condición que el objeto puerta tendría que estar inactivo para poder cambiar de escena, pero el objeto puerta, si nos fijamos en su script, no se pondrá inactivo hasta que no hagamos clic sobre el.
Guarda todos los scripts, y ejecuta el juego. Prueba el juego y asegúrate que entiendes el código, y la lógica de como funciona. Este es uno de los puntos críticos en el diseño de las aventuras, ya que si no se aprende correctamente, no podremos conseguir potencia en nuestros juegos.
Importante: un punto importante dentro de wme, son las rutas de los ficheros. Hemos visto que en:
Game.ChangeScene(“scenes\room\room.scene”);
No empezamos la ruta desde la carpeta data, nunca incluiremos la raíz(data) en la ruta que usamos en las llamadas a ficheros. ¿Por que? Porque si lo incluimos, solo funcionaria mientras lo usemos en el modo depuración, una vez que lo compilemos, si ponemos la raíz en la ruta, no funcionará. Esto se aplica a todas las llamadas a ficheros. Si te ocurre esto, sufrirás pesadillas, imagina que la carpeta data es la c: y todo lo referenciamos a partir de ahí, y la carpeta data no la nombramos.
Veamos la ultima parte de este capitulo, donde hablaremos de los daemons(demonios)
¿que es un demonio?
Un demonio no es mas que un programa interno que se encarga de ofrecer funcionalidades a un programa externo, por ejemplo cuando estamos jugando a una aventura, y de repente se lanza un vídeo, pues para que ese vídeo se pueda lanzar, es necesario un reproductor de vídeo, pues esto por ejemplo es un demonio, después también los hay para sonidos,… Aquí los veremos de pasada, y ya mas adelante los explicaremos mas a fondo.
Antes de hablar de los daemons, veamos cuatro métodos mas:
Game.AttachScript(filename); → Añade un archivo de script al juego, haciéndolo global para todo el juego. Este script estará activo hasta que se desvincule, o termine.
Game.DetachScript(filename); → Desvincula un script del juego.
Scene.AttachScript(filename);→ Añade un archivo de script a la escena. Este script estará activo hasta que el jugador cambie de escena, se desvincule, o termine.
Scene.DetachScript(filename);→ desvincula un script de la escena.
Claro que podemos añadir un script a la escena en el editor de escenas, o un script a Game en la carpeta script del proyect manager pero ¿y si queremos añadir un script en medio de la partida?. Pues por esto son importantes y útiles estas funciones, ahora mas adelante veremos algunos ejemplos.
El siguiente comando que vamos a ver, es totalmente necesario para el demonio(daemon) de escritura. Se trata del comando Sleep:
Sleep(tiempo);
Este script paraliza un script por un periodo de tiempo que es pasado como parámetro en milisegundos, es decir sleep(1000); pararía el script durante 1 segundo.
Sleep tiene dos propósitos, el primero liberar al proceso, y dar paso a otros procesos en el ordenador, sino se hace esto, se pueden producir errores, incluso llegar a bloquear el pc.
var a = 0; while (1) // esto es un bucle infinito { a = a + 1; if (a > 100) a = 0; }
Nunca hagas esto, puede bloquear tu equipo. El script ocupa todo el procesador y el resto del juego podra dejar de funcionar. ¿Como solucionarlo?
var a = 0; while (1) { a = a + 1; if (a > 100) a = 0; Sleep(1); // detiene el control del script durante 1 milisegundo. }
Esta es la forma recomendable de programar bucles infinitos o con posibilidad de ser muy largos en wme, es decir en cada interacción del bucle, hacemos una pequeña pausa, para detener script, dejando paso a otros script en el procesador y evitando que este se sature.
Necesitamos un comando mas:
Game.Msg(texto) – esta función como ya hemos visto, nos muestra en pantalla un mensaje de depuración. Este comando es muy útil, porque nos servirá para controlar el estado de las variables y los objetos durante el modo de programación.
Lo que vamos a hacer es añadir a nuestra escena, una serie de lineas. Cuando el personaje examina la puerta, se dará cuenta que hay una bomba, de esta manera si el personaje no se aleja de la puerta a tiempo, volveremos a cargar la escena desde el principio, esto es muy común en los juegos de aventuras cuando queremos representar que nuestro personaje a muerto.
Primero, crearemos un nuevo script en la carpeta scr de nuestra escena llamado bomba.script.
Consejo: Es posible ir a esta carpeta y crear el fichero manualmente, creamos un fichero bomba.script, y después podremos acceder a el desde el administrador de proyectos de wme, es una forma diferente de crear nuevos ficheros.
Debemos modificar nuestro script de la puerta que veníamos creando durante este capitulo.
#include “scripts\base.inc” on “LeftClick” { Game.interactive=false; // Desactivamos el control del personajes actor.GoToObject(this); // El personaje camina hacia el objeto(puerta) this.Active= false; //Desactivamos la puerta actor.Talk(“Oh no, hay una bomba de tiempo sobre la puerta, debo escapar antes de que explote.”); // El actor hace un comentario Scene.AttachScript(“scenes\warehouse\scr\bomba.script");/*añadimos nuestro script de la bomba al juego */ Game.Interactive=true; // devolvemos el control del personajes }
Simplemente hemos modificado lo que decía nuestro actor, y hemos añadido una linea(Scene.AttachScript(“scenes\warehouse\scr\bomba.script");) que lo que hace es cargar un script en nuestro juego, de esta manera el script comenzará a ejecutarse, cuando hagamos click con el botón izquierdo sobre la puerta.
Bien, ahora vamos a definir nuestro fichero bomba.script donde incluiremos un contador que lo que hará sera que si pasa ese tiempo y no hemos escapado, la escena se cargará desde el principio.
Luego el script bomba.script tendrá el siguiente aspecto:
include “scripts\base.inc” for(var tiempo=6; tiempo>-1; tiempo = tiempo -1) /* Iniciamos un bucle que llevara la cuenta desde que pulsamos la puerta */ { Game.Msg(“cuenta atrás: “ +tiempo);//Mostramos el tiempo que nos queda Sleep(1000); // Detenemos la ejecución del script durante 1 segundo } Game.Interactive=false; //Desactivamos el control del jugador actor.Talk(“estoy muerto, intentalo de nuevo); //Hacemos que el actor hable Game.ChangeScene(“scenes\warehouse\warehouse.scene”);/*Volvemos a cargar la escena, en esta función, el parámetro se refiere al archivo de escena con el que estábamos trabajando, debe tener el nombre que nosotros le hubiéramos indicado */ var puerta = Scene.GetNode(“puerta”); //Obtenemos el objeto puerta en una variable puerta.active= true; // Volvemos a hacer activa la puerta Game.Interactive=true; // Devolvemos el control del jugador //Fin de nuestro script bomba.script
Como ves la forma de trabajar siempre es muy parecida, desactivamos el control del jugador cuando este va a realizar alguna acción y siempre lo devolvemos al final. Así que nada, tenemos escrito nuestro script de la puerta, y nuestro script de la bomba que hará que si el jugador no abandona la escena en el tiempo establecido, en este caso son 7 segundos, ya que el bucle( “for(var tiempo=6; tiempo>-1; tiempo = tiempo -1)” ) realiza 7 interacciones, desde 6 hasta 0 contando ambos.
Espero que se vayan entendiendo los script, y es muy importante que los analicéis y lo destripéis hasta que vayáis entendiendo cada linea, de esta manera, cogeremos soltura rápidamente, ya que si pasamos de algo que no entendemos, cada vez se irán añadiendo nuevas cosas y llegara un punto en que no entendáis nada, por eso es recomendable que entendáis bien cada script.
Bien, veamos ahora el script de la región que llamamos salida, salida.script :
#include "scripts\base.inc" on "ActorEntry" { var puerta = Scene.GetNode("puerta"); /* Almacenamos el objeto puerta en una variable en este caso el parámetro “puerta” debe ser el nombre que le diéramos a nuestra puerta en el editor de escenas */ Game.Interactive = false; //Desactivamos el control del personaje if (puerta.Active) // Preguntamos, esta la puerta activa? { actor.Talk("no volveré a mi piso hasta que no sepa que no puedo entrar en el almacén"); /* El actor realiza un comentario si no hemos echo click sobre la puerta */ } else //Si la puerta esta desactivada { Scene.DetachScript("scenes\warehouse\scr\bomba.script"); /* Descargamos el script de la bomba */ actor.Talk("uff! Estuvo cerca"); // Nuestro personaje suelta un comentario Game.ChangeScene("scenes\room\room.scene"); //Cambiamos la escena } Game.Interactive = true; // Devolvemos el control del jugador }
Guarda todos los script, y ejecuta el juego para comprobar si todo funciona correctamente.
Para finalizar este capitulo, realizaremos un pequeño cambio juego, no es necesario pero es para que veáis como resolver lo mismo de otra forma, si os fijas, en cada script debemos hacer uso del método Game.GetNode(“puerta”); para evitar tener que hacer esto en cada script, es posible usar una variable global que guarde si la puerta fue clickeada o no, de esta manera no será necesario desactivar la puerta, y mas adelante el jugador podrá seguir interactuando con la puerta, pero si ya habíamos realizado un clic anteriormente, el script bomba no se volverá a ejecutar, dando así potencia al juego.
Bien, veamos los cambios que debemos realizar en nuestros script para realizar lo mismo mediante una variable global.
bomba.script
#include “scripts\base.inc” for(var tiempo=6; tiempo>-1; tiempo = tiempo -1) /* Iniciamos un bucle que llevara la cuenta desde que pulsamos la puerta */ { Game.Msg(“cuenta atrás: “ +tiempo);//Mostramos el tiempo que nos queda Sleep(1000); // Detenemos la ejecución del script durante 1 segundo } Game.Interactive=false; //Desactivamos el control del jugador actor.Talk(“estoy muerto, intentalo de nuevo); //Hacemos que el actor hable Game.ChangeScene(“scenes\warehouse\warehouse.scene”);/* Volvemos a cargar la escena, en esta función, el parámetro se refiere al archivo de escena con el que estábamos trabajando, debe tener el nombre que nosotros le hubiéramos indicado */ var puerta = Scene.GetNode(“puerta”); //Obtenemos el objeto puerta en una variable puerta.active= true; // Volvemos a hacer activa la puerta global puertaClicked = false; /* Esta es la nueva linea añadida, con la que controlaremos si la puerta fue clickeada o no.*/ Game.Interactive=true; // Devolvemos el control del jugador
Fichero salida.script:
#include "scripts\base.inc" on "ActorEntry" { var puerta = Scene.GetNode("puerta"); /* Almacenamos el objeto puerta en una variable en este caso el parámetro “puerta” debe ser el nombre que le diéramos a nuestra puerta en el editor de escenas */ Game.Interactive = false; //Desactivamos el control del personaje global puertaclicked; /* Llamamos a la variable global que almacena si la puerta fue clikeada*/ if (!puertaclicked) // Con la variable global preguntamos si puertaclicked=false { actor.Talk("No volveré a mi piso hasta que no sepa que no puedo entrar en el almacén"); /* El actor realiza un comentario si no hemos echo click sobre la puerta */ } else //Si puertaclicked=true { Scene.DetachScript("scenes\warehouse\scr\bomba.script"); /* descargamos el script de la bomba */ actor.Talk("uff! Estuvo cerca"); // Nuestro personaje suelta un comentario Game.ChangeScene("scenes\room\room.scene"); //Cambiamos la escena } Game.Interactive = true; // Devolvemos el control del jugador }
Como podemos ver, en este caso ya no es necesario hacer uso del atributo Active del objeto puerta para saber si esta fue clickeada o no, esto da la ventaja que ya comentaba antes, que la puerta puede seguir activa después de hacer el primer clic, con lo que damos la posibilidad de que se pudiera seguir interactuando con ella.
Hemos venido trabajando con un proyecto de ejemplo muy simple,en el próximo capítulo empezaremos un proyecto desde 0, espero que hayas entendido estos capítulos anteriores porque son cruciales para seguir con lo que vamos a ver ahora.