Mostrando entradas con la etiqueta dev. Mostrar todas las entradas
Mostrando entradas con la etiqueta dev. Mostrar todas las entradas

viernes, mayo 08, 2020

Lisp y Naughty Dog

Lisp es uno de los lenguajes de programación mas antiguos (el segundo de alto nivel, solo posterior a Fortran) y hoy en día, en diferentes dialectos o inspirando otros lenguajes, aun sigue bastante vivo. Sin embargo, a pesar de que una buena implementación es lo bastante compacta para ser un lenguaje de script para juegos, a poca  gente se le ocurriría usarlo como lenguaje principal en el mundo de los videojuegos. Si exceptuamos a Naughty Dog, claro.

Por que como Andy Gavin cuenta, empezaron usando su propia versión de Lisp en el cutre clon de Mortal Kombat llamado Way of the Warrior para implementar las maquinas de estado. La cosa continuo en su siguiente saga, Crash Bandicoot, creando una versión de Lisp llamada GOOL (Game Oriented Object Lisp), que usaron para scriptar el gameplay de los objetos del juego.

El código de GOOL esta basado en los estados de los objectos, que implementaban su jugabilidad con diferentes bloques de código. Permitía ejecutar trozos de código estilo corutina: el código marcado como ":code" se ejecuta hasta que encuentra una variante del comando "frame", que pasa el control al siguiente bloque. Por ejemplo, aquí repite una animación hasta que colisiona con algo
:code (defgcode (:label play animation)
  ; play the animation until this object is colliding with
  ; another, then change states
   (until (status colliding)
    (play frame group animation))
    (goto collided)))

Dentro de los estados también permitía código ejecutado cada frame, marcándolo con ":trans". Por ejemplo, aquí rota un objecto 10 grados cada frame hasta 180.
:trans (defgcode (:label turn 180)
  ; set the y rotation 10 degrees closer to 180 degrees
   (setf roty (degseek roty (deg 180) (deg 10))))
GOOL también contaba con un sistema de eventos tan sencillo de usar como este ejemplo para colisiones en la cabeza
(send event hit on the head (find the nearest object))
Vamos que si podías sobrevivir a usar LISP tenias a tu disposición un lenguaje de script muy potente para la época y la plataforma.

Y todo llego a un nivel mas con GOAL (Game Oriented Assembly Lisp) que se usó en la saga de Jak & Daxter. En este caso nada mas y nada menos que el 98% del código del juego estaba escrito en esta variante de Lisp. Esto les llevo a unos cuantos quebraderos de cabeza a la hora de encontrar programadores, ya que en el mundo de los videojuegos es relativamente fácil encontrar expertos en C++, pero es muy difícil reclutar a expertos en Lisp. No hay mucha información mas sobre GOAL, a parte de que esta implementado con Allegro CL y que, como su nombre indica, se compila directamente en assembler para la PS2.

Y vaya, parece que ND estaba muy augusto con su engine hasta que la unión con Sony les obligo a programar en C++, para que pudieran compartir código con otros equipos dentro de la compañía japonesa. Eso si, aunque ya no sea su lenguaje principal, se sigue usando como lenguaje de script, como demuestra esta presentación sobre Uncharted 2 en la que se ve que aun siguen usando una nueva versión de Lisp para scriptar partes del juego.

viernes, abril 22, 2016

Como usar Lua como sistema multi-tarea para cutscenes o IA en Unity


Trabajando en la industria del videojuego, llevo ya unos cuantos años usando sistemas de scripts empotrados en juegos para controlar las cutscenes, la IA y otros elementos varios del juego.

Menos algunas excepciones eran sistemas de script muy sencillos y específicos para ciertas operaciones o para maquinas poco potentes, así que principalmente he estado usando sistemas propios creados a medida de la tareas a realizar (bueno, también cree un interprete de Forth, pero este fue mas como un reto que otra cosa).

Sin embargo el tamaño de los juegos en los que estoy metido, y por tanto la variedad, complejidad y extension de los scripts a utilizar, ha crecido hasta tal punto que ya merecía la penar utilizar un lenguaje empotrado de uso general como Lua.

Usando Lua perdemos eficiencia y la capacidad de personalización de los scripts a medida, pero a cambio ganamos un lenguaje de programación completo, ademas de contar con muchas librerías y soporte de una comunidad.

Y el origen de este articulo viene precisamente de no poder personalizar Lua fácilmente para ejecutar varios scripts a la vez a modo de multi-tarea utilizando los wrappers en C# para Unity.
Tal vez en juegos de aventura como Tokyo Super Night o incluso RPGs por turnos como Curse of the Red Forest es posible tener un solo hilo de ejecución. Pero normalmente quieres tener varios: por ejemplo uno por cada IA activa, otro para cut-scenes, unos cuantos para gestionar triggers, etc..

Vamos a imaginar una situación mas concreta, una cutscene de un JRPG en la que dos personajes se mueven hasta un punto y inician una conversación cuando ambos han llegado. Podríamos escribirlo así:

function my_cutscene()
  move_npc(npc1,{120,120,0})
  move_npc(npc2,{120,100,0})
  say(npc1, "Hola npc2!")
  say(npc2, "Hola npc1!")
end


A primera vista es un código fácil de entender, ¿no? El problema es que no estamos sincronizando el movimiento de los NPCs con el dialogo para que empiece solo cuando ambos hayan llegado al punto de destino.

Simplemente no podemos bloquear la ejecución en move_npc, porque impediría ejecutarse a la siguiente instrucción (y cualquier otro script que haya activo), pero si podemos esperar a que terminen de moverse con un comando nuevo:

move_npc(npc1,{120,120,0})
move_npc(npc2,{120,100,0})
-- El script parara de ejecutarse hasta que todos los personajes se paren.
say(npc1, "Hola npc2!")
say(npc2, "Hola npc1!")
wait_move()

Este tipo de scripts funcionaria si solo tuviéramos este script en ejecución. Y aun así, el wrapper de Lua para Unity que usábamos no soportaba pausar la ejecución de la VM de Lua a mitad de un script para retomarla luego (o al menos yo no encontré como hacerlo), así que este método tampoco funcionaba.

Lo que hacíamos para ejecutar scripts con "pausa" para sincronizar era aprovechar que nuestro engine para juegos de aventura soportaba bloques de codigo Lua entre texto de diálogos, al estilo de los scripts para visual novels:

%{
  move_npc(npc1,{120,120,0})
  move_npc(npc2,{120,100,0})
  wait_to_finish_all_moves()
}%
%{ say(npc1) }% Hola npc2!
%{ say(npc2) }% Hola npc1!

   
En nuestros scripts el código Lua va entre %{ }% y cada bloque se ejecuta entero, pero se pausa para mostrar el texto entre bloques en pantalla (si lo hay) y continua con el siguiente bloque. Esta solución un poco cutre, nos valía para las pocas sincronizaciones que teníamos en juegos de aventura o por turnos. Pero para Adel necesitábamos una sincronizacion mas completa.

En principio deje aparcado como mejorar este sistema de scripts, pero un día, revisitando la página del nuevo juego de uno de los maestros del videojuego, Ron Gilbert, encontré una posible solución. En este articulo, se explicaba como usar las co-rutinas que incluyen algunos lenguajes de programación para simular multi-tarea, al estilo de como lo hacia el mítico SCUMM. Y aquí es cuando descubrí que Lua cuenta con co-rutinas en su funciones principales y, por lo tanto, lo podía utilizar para simular multi-tarea dentro de los scripts. Esto no es para nada nuevo, ya existen scripts para gestionar las tareas con subrutinas. Y investigando un poco, usar co-rutinas para juegos, incluso triple-A, parece ser algo muy común: las saga Uncharted (con su propio lenguaje de script basado en Lisp) o Fable II y III (usando Lua, como es nuestro caso).

Ninguna de los scripts que gestionaban de multi-tarea en Lua con co-rutinas que encontré en la red me convenció, así que decidí crear el mio propio a medida (ques lo que podéis descargar junto a un proyecto de ejemplo de Unity mas abajo).

Pero llegados a este punto, ¿que son exactamente las co-rutinas? Si programáis en Unity seguramente ya las habréis visto usadas en C#. Son métodos o funciones ejecutados paralelamente a otros programas, pero no a la vez y no con cambio automático de tarea. Así una co-rutina debe dejar paso a los demás hilos de ejecución normalmente con el un comando yield y volverá a ejecutarse después de un tiempo establecido o cuando lo despierte otro hilo. Aunque nunca sera tan optimo cono usar los threads del sistema, usar co-rutinas nos libra de muchos de los problemas de programar en paralelo usando threads, al saber exactamente cuando vamos a pasar el control a otro hilo, y ademas nos permite tener muchísimos mas hilos de ejecución (tareas en nuestro caso) de los que permiten los thread del Kernel.

La pequeña librería que hice permite ejecutar varias tareas, pararlas y pausarlas por un tiempo o hasta que se genere una señal o simplemente por un frame (para recordar al mítico DIV, que contaba también con el mismo tipo de multi-tarea hace ya casi 20 años).

Creo que todo queda mas claro aplicándolo al ejemplo del principio:

function my_cutscene()
  -- Iniciamos una tarea para mover a cada personaje
  Task:start("move_mycutscene",move_npc,npc1,{120,120,0})
  Task:start("move_mycutscene",move_npc,npc1,{120,120,0})
  -- Mientras no ternminen, esperamos
  while Task:alive("move_mycutscene") do
    Task:frame()
  end
  -- Mostramos el dialogo
  say(npc1, "Hola npc2!")
  say(npc2, "Hola npc1!")
end

--Aqui iniciamos la cutscene
Task:start("cutscene",my_cutscene)

Y de paso la función say también utiliza el sistema de tareas para esperar a que se muestra un mensaje antes de continuar:

function say(npc_id,text)
  -- La parte en Unity mostrara el mensaje con la cara 

  -- del personaje
  game.say(npc_id,text)
  -- Y esa parte en Unity también envía siempre a la señal "end-dialog" cuando
  -- acaba de mostrar el texto, así que la esperamos

  Task:wait_signal("end-dialog")
end

Y ya tenemos nuestro sistema multi-tarea para cutscenes, IA y lo que necesitemos. Este ejemplo es muy sencillo, pero imaginad que hasta la saga Uncharted ejecutaría un script parecido cada vez que un NPC acompañante se para a esperarte antes de continuar la escalada.

En el link de abajo, tenéis un ejemplo prestado del articulo que me inspiro a crear este sistema, implementado con un intérprete de Lua, mi mini-librería y unos gráficos de opengameart.org.



Descarga

No soy un experto en Lua y es la primera vez que trabajo con este tipo de sub-rutinas, así que cualquier reporte de bugs, posibles mejoras o comentario sobre este ejemplo serán bien recibidas.

lunes, mayo 12, 2014

Como hacer un juego top-down 2D a lo Zelda en Unity



Si el año pasado durante la Golden Week (como las vacaciones de Semana Santa en Japón, pero sin procesiones) hizo ese micro-clon de Diablo + Gauntlet llamado Dungeons of Diablet en Unity, esta año me había decidido a hacer un juego un poco mas retro. Siempre había querido hacer un juego a lo Zelda, pero no como el de NES. Como muchos yo nunca pude jugar al de NES en su tiempo, si no que guardo mejor recuerdo del de Game Boy, junto con otros muchos juegos de la portátil de Nintendo.

El problema es que esta vez, por varias razones, he estado muy ocupado durante la Golden Week. Pero durante un descanso probé a montar el esqueleto de un juego 2D y los resultados de unos 15 minutos con Unity me encantaron, así que decidí continuar con unas pocas horas de desarrollo al día siguiente. Por supuesto ese tiempo no es suficiente para terminar el juego, pero mas o menos se puede ver el resultado en el vídeo de mas arriba.

Con calma (ya que también tengo a The Curse of The Red Forest en marcha) espero completarlo y hacerlo un juego completo.

Aah, y podéis probar este esqueleto de juego aquí.

martes, marzo 18, 2014

Mi nuevo proyecto: "The Curse of the Red Forest"


Los que leéis este blog, escucháis mi micro-podcast en audioboo o me seguís en Twitter sabréis que desde hace tiempo estoy trabajando en un nuevo proyecto personal, después de terminar "The Island of the Oracle 3D". Aunque ya había anunciado el titulo furtivamente en Twitter, ahora mismo estoy preparando la presentación en sociedad del juego.

Se trata de "The Curse of the Red Forest", un RPG clásico en primera persona con inspiración totalmente anime. Como comente en un audioboo, para este juego estoy utilizando tanto material creative commons como material de pago para tener mas libertad a la hora de crear el tipo de juego y historia que quiero contar.

Estoy preparando el juego para Android y iOS, que estarán listas a finales de esta primavera. A la estoy haciendo los arreglos para una eventual versión para Playstation Mobile. La versión para PSM permitiría sacar el juego para PS Vita (lo que me hace mucha ilusión), pero todo depende de que se libere el exportador para esta plataforma de Unity, que ahora mismo esta en beta cerrada.

Por de pronto aquí os dejo la pagina en IndieDB donde he registrado el juego y la web oficial. En breve tendréis un nuevo audioboo explicando los avances del juego y la semana que viene publicare el primer teaser trailer del juego. ¡Así que estad atentos!




viernes, diciembre 13, 2013

Sistemas para crear aventuras conversacionales (III) : INFOCOM


Zork I para TRS-80, una de las versiones mas antiguas

Introducción


De entre todas las compañías que se dedicaron a crear aventuras conversacionales en los 80, INFOCOM es seguramente una de las mas antigua y de las mas recordadas en los paises donde llegaron sus juegos. Cuando las aventuras para ordenador no dejaban de ser clones de aventuras de Scott Adams o de una simplicidad similar, INFOCOM introdujo aventuras que eran verdadera ficción interactiva. Textos largos y descriptivos, parser de texto avanzado y complejo y unas herramientas para hacer aventuras cuya influencia aun esta viva hoy en día.

Pero hagamos primero un poco de historia. Y la historia de INFOCOM esta ligada a Zork, una aventura inspirada en la original creada por varios estudiantes de MIT. Esta versión primigenia de Zork esta programando en MDL, un lenguaje basado en LISP,usado para la investigación de varios temas relacionados con inteligencia artificial dentro del MIT. Zork fue portado por un hacker a Fortran y acabo distribuyéndose por todos los main frames de la época. La historia podría haber acabado aquí, como tantas otras aventuras para grandes ordenadores de la época pero sucedió que el grupo de estudiantes que había creado Zork originalmente se decidió por crear una empresa aprovechando el boom de los micro-ordenadores de finales de los 70. Su intención era crear aplicaciones, no juegos, pero al no tener ninguna aplicación pensada, se decidieron por portar Zork a los micros de la época. Y aquí comienza la prolífica historia aventurera de INFOCOM .

Como se hicieron los juegos de INFOCOM 


Hecho el prefacio histórico, vamos a centrarnos en como INFOCOM  hacia sus juegos. La primera versión, no comercial, de Zork estaba escrita en MDL y el código esta disponible. Pero al ser un lenguaje con muy poca difusión y apenas documentación  se hace difícil analizar el código (que es bastante complejo para la época). Mejor que eso nos vamos a centrar en los ports para micro-ordenadores, que guardan relación con el MDL, pero están mucho mejor documentados y por razones que explicare mas adelante es también mucho mas claro.

El primer problema que se encontró INFOCOM para portar Zork a micros fue el mismo que tuvo Scott Adams, la falta de memoria. Pero a diferencia de Adams, INFOCOM decidio centrarse solo en sistemas con disco, lo cual ya les daba bastante soltura en cuanto espacio, pero aun así tuvieron que comprimir bien el texto y implementar su propio sistema de memoria virtual (algo que era casi experimental en ese tiempo) para que Zork cupiera en los micros de primera generación.

Otro problema a solucionar era que, aun centrándose en sistemas con disco, la variedad de micros a finales de los 70 hacia que el mercado estuviera muy disperso, por lo que para maximizar los beneficios los juegos tenían que ser portados a varios sistemas. La solución de INFOCOM es casi obvia hoy en día: diseñaron una maquina virtual, la maquina Z. Con esta solución solo tenían que portar el código de la máquina Z a cada sistema (un programa llamado ZIP), dejando el código de cada juego tal cual. Esta maquina esta, por supuesto, orientada a reproducir aventuras, y esta tan bien diseñada que sigue siendo la base para sistemas de aventuras modernos como Inform.

La máquina Z


Así que la maquina Z implementaba funciones básicas de entrada y salida, memoria virtual y el sistema de compresión  dejando todo lo demás (incluido el parser) para ser programado dentro de ella. Lo bueno de que la Z-machine fuera lo mas simple posible es que todo Z-code, el código que interpretaba, no tenia que ser portado. Con lo cual si las partes mas complejas del juego, como el parser, se creaban en código-Z, ya no era necesario re-escribirlo para todos los ordenadores de la época; ganando en potabilidad.

La técnica de memoria virtual (algo muy nuevo en la época) les permitía tener en memoria solo las partes del juego que se estaban usando en ese momento. Cuando se requería algo que no estaba en memoria se cargaba de disco, borrando alguna parte de memoria cuando fuera necesario. Para poder hacer esto, la Z-machine clasificada en dos tipos de bloques de memorias: puros e impuros. Los bloques puros eran información que no se modificaba nunca como las cadenas de texto y las definiciones de objetos (que eran todos estáticos). Los impuros eran a su vez los que si se modificaban, como los flags de los objetos, su posición o las variables globales. Así que cuando fuera necesario mas espacio en memoria del disponible, la maquina-Z solo tenia que borrar cualquier bloque "puro" y reescribirlo con la nueva información. Si volvía a hacer falta el bloque borrado, sabiendo que es invariable, solo habría que re-leerlo del disco. Los bloques impuros debían permanecer siempre en memoria, y es lo que mas limitaba la RAM mínima para ejecutar los juegos. Los primeros juegos apenas requerían RAM, unos 32Kb, pero los últimos juegos, mas avanzados, requerían muchas mas memoria y prácticamente solo funcionaban en maquinas de 16 bits.


La memoria virtual, junto con un inteligente algoritmo de compresión de textos hicieron que los juegos de INFOCOM fueran los mas avanzados, complejos y largos durante años.

El Z-code era de un nivel parecido al ensamblador con algunas instrucciones especiales. Por lo tanto de crear los juegos directamente en Z-Code hubiera sido una tarea completísima. Usando su experiencia con grandes maquinas, decidieron crear un lenguaje especial de alto nivel para crear aventuras que se compilara generando z-code. Este lenguaje no era ni mas ni menos que un MDL (o sea LISP) muy simplificado, quitando cualquier cosa que no hiciera falta para hacer juegos de aventuras y añadiendo cosas que ayudaran al desarrollo.

Mirando por Internet, ninguno de estos compiladores de ZIL (Zork Implementation Language) ha sobrevivido hasta nuestra época, pero si alguna de la documentación para crear juegos, con lo cual podemos saber mas o menos como funcionaba. Y para ser un sistema de finales de los 70-principios de los 80, era toda una maravilla al servicio del creador de aventuras. Probablemente hasta la llegada de los sistemas especializados para PC a mediados de los 90, como TADS o Inform, no hubo mejor entorno para la creación de conversacionales.

El Zork Implementation Language: ZIL


Pero vamos a meternos en materia. La programación se realizada en este pseudo-LISP y la visión desde el punto del programador era bastante orientada a objetos, aunque la Programación Orientada a Objectos aun no se había desarrollado del todo por entonces, así que tiene algunas cosas un poco "raras", vistas hoy en día.

Lo primero vamos a estudiar la definición de una habitación:

<ROOM LIVING-ROOM
    (LOC ROOMS)
    (DESC "Living Room")
    (EAST TO KITCHEN)
    (WEST TO STRANGE-PASSAGE IF CYCLOPS-FLED ELSE 
"The wooden door is nailed shut.") 
    (DOWN PER TRAP-DOOR-EXIT)
    (ACTION LIVING ROOM-F)
    (FLAGS RLANDBIT ONBIT SACREDBIT)
    (GLOBAL STAIRS)
    (THINGS <> NAILS NAILS-PSEUDO)> 

Lo primero que salta a la vista es que se usan a la vez los paréntesis típicos de LISP con partes que se señalan con < y >, como las definiciones de habitaciones, objetos y las llamadas a funciones de sistema.

En todo caso, el lenguaje funciona como LISP, de forma que todo son listas de elementos entre paréntesis (o "<" ">"). Asi que una habitación es simplemente una lista con el identificador al principio ("ROOM LIVING-ROOM") seguida de las propiedades de la habitación. El primero "LOC" es el lugar donde esta el objeto, porque en realidad las habitaciones se tratan como objetos, solo que están siempre en el objeto especial ROOMS. Seguidamente tenemos las salidas, incluyendo una salida condicional que es bastante auto explicativa. La salida hacia abajo, mas complicada, en realidad llama a la función TRAP-DOOR-EXIT para decidir si se puede pasar o no.

La siguiente linea, ACTION, define la función que tratara algunos asuntos de la habitación, lo veremos mas adelante. Luego tenemos los objetos globales que están presentes en la habitación y la ultima linea es indescifrable para mi. Como podéis ver es un lenguaje bastante potente para definir cosas (contando en el año que estaban) y que a mi gusto me parece mas claro que lenguajes mas nuevos como Inform.

Habiendo visto una habitación, el código de un objeto es también bastante claro

<OBJECT LANTERN
    (LOC LIVING-ROOM)
    (SYNONYM LAMP LANTERN LIGHT)
    (ADJECTIVE BRASS)
    (DESC "brass lantern")
    (FLAGS TAKEBIT LIGHTBIT)
    (ACTION LANTERN-F)
    (FDESC "A battery-powered lantern is on the trophy case.")
    (LDESC "There is a brass lantern (battery-powered) here.")
    (SIZE 15)>

Aparte de los parámetros ya explicados tenemos diferentes descripciones para cuando se examine o se describa con la habitación, su peso, los flags que indica que da luz y se puede coger junto con los adjetivos y sinónimos que el jugador puede usar. 

Las funciones y el parser


Tal vez la parte mas potente de ZIL en si es la capacidad de crear funciones, que se pueden utilizar para crear la interacción con el juego. Se definían así:

<ROUTINE TURN-OFF-HOUSE-LIGHTS ()
            <FCLEAR ,LIVING-ROOM ,ONBIT>
            <FCLEAR ,DINING-ROOM ,ONBIT>
            <FCLEAR ,KITCHEN ,ONBIT>>

Como podéis ver vuelven a aparecer los "<" ">", tanto para definir la rutina como para las función de sistema FCLEAR (pone a cero un flag de un objeto, en este caso el de la habitación tiene luz). Las funciones admiten parámetros, variables locales y hasta parámetros opcionales, en la forma:

< ROUTINE CALLEE (X "OPT" Y "AUX" Z)
            <some-stuff>> 

Digamos que el lenguaje tenia muchas comodidades que tardarían en llegar años al a programación en general!

Bien, pues estas funciones se utilizaban para interpretar las acciones del usuario. Primero el parser léxico identificaba un verbo, objeto directo y indirecto (si están presentes). Entonces dará la oportunidad a cada uno de estos objetos (o mas bien a su función ACTION) en el orden inverso de resolver el comando o si no dará el típico de "No puedes hacer eso". Para ello utiliza una función COND, que es una lista de pares condiciones - acciones, de las que solo se ejecute la primera que se evalúe a cierto con la forma:

<COND (<predicado-condicion-1> 
           <hacer-algo-1>)
         (<predicado-condicion-2>
           <hacer-algo-2>)
         (<predicado-condicion-3>
           <hacer-algo-3>)> 

En cada predicado podemos comprobar si el verbo y los objectos cumplen ciertas condiciones o si el estado del juego es el correcto para activar un programa que muestre un mensaje, mueva objetos, etc. Cuando se empiezan a amontonar paréntesis es un poco complicado, pero en realidad es mucho mas fácil de definir y releer condiciones complejas que con otros sistemas de los 80. Por ejemplo, podemos responder una acción así al comer un aguacate envenenado:

<ROUTINE AVOCADO-F ()
     <COND (<VERB? EAT> 
               <SETG PLAYER-POISONED T>
               <REMOVE ,AVOCADO>
               <TELL "You begin to feel sick.">)>>

Creo que es bastante auto-explicativo, pero SETG cambie el valor de una variable global, en este caso a cierto (T, es decir true), REMOVE quita un objeto (cambiando su propiedad de LOC, en realidad los objetos no se pueden destruir) y TELL muestra un mensaje por pantalla.

Las acciones de habitación, mencionadas al principio, en realidad lo hacen nada con el input del jugador, si no ejecutan ciertas funciones necesarias en cada habitación. Esta función recibe un parámetro en el que se especifica que tiene que hacer, siendo el mas habitual "M-LOOK", para describir la habitación como aquí:

<ROUTINE CAFETERIA-F (RARG) 
   <COND (<EQUAL? .RARG ,M-LOOK>
         <TELL "This is a lunch room, with windows overlooking a loading dock. ">
         <COND (<IN? LUNCH-CROWD ,CAFETERIA>
                <TELL "Every table is jammed with patrons. ">)>
                <TELL "The only exit is north." CR>)>>

Esto es especialmente útil para habitaciones que cambian con el tiempo o si hay algún objeto especial dentro. También hay funciones adicionales para cuando el jugador entra, sale o realiza una acción dentro de cada habitación; así que podemos controlar todo lo que ocurre dentro de la habitación.

Aun quedan muchas mas cosas, como crear personajes interactivos, timers, la definición del léxico... pero todo esto se hace de una manera parecida a la que hemos visto, así que si tenéis interés en saber aun mas de las interioridades de ZIL os recomiendo echar un vistazo a la bibliografía.

Conclusiones


Como podéis ver es un lenguaje muy potente, que permite especificar acciones complejas de una manera sencilla. Y todo en una época cuando muchos programadores la herramienta mas elaborada que tenia era un BASIC de 8 bits. Desde luego este sistema de creación de aventuras se tradujo en que las aventuras de INFOCOM fueran las mas depuradas, complejas y avanzadas durante toda su vida. Digamos que ello tenían una sierra mecánica para cortar arboles cuando la competencia usaba una lima de uñas.

Una parte de estas herramientas estaban tan bien diseñadas que sobrevivieron durante años, llegando hasta hoy en día. Me refiero al estándar de Maquina-Z, que esta aun vivo y portado a todos los sistemas existentes gracias a que fue la plataforma que Graham Nelson decidió para que su compilador Inform. Y aun hoy en día se crean aventuras con esta herramienta para las versiones clásicas de la máquina-Z. Desde luego el estándar ha sido extendido para soportar gráficos, sonido y quitar el limite de memoria entre otras cosas; pero hoy en día no hay ningún interprete de aventuras que no soporte el estándar Z.

Por desgracia, mientras que la máquina-Z aun sigue viva hasta hoy, el compilador ZIL se ha perdido en el tiempo y solo nos queda su documentación...


Update 2019


Recientemente se ha liberado el codigo fuente original en ZIL de todos los juegos de Infocom, como el mismo Zork I. No se ha recuperado el compilador original, pero solo con los fuentes podremos aprender nuevas cosas de como trabajaba Infocom.

Bibliografía y links de interés

  • Post recomendadísimo en "The Digital Antiquarian" sobre las herramientas de INFOCOM .
  • Documentación interna de INFOCOM sobre ZIL que ha sobrevivido hasta nuestros días.
  • Entrada en Mobygames de Zork I, de donde he sacado la captura de esta entrada.
  • Frotz, un interprete moderno y portable de la máquina-Z.
  • (Nuevo!) Repositorio con todos los sources de Infocom


Entradas anteriores





viernes, noviembre 15, 2013

Como simular el movimiento de un RPG clásico en primera persona con Unity 3D

Eye of the Beholder, Ishar, Dungeon Master, Wizardray... Son solo alguno de los mas famosos nombres de RPGs en primera persona que triunfaron en los '80 y principios de los '90. Debido a limitaciones técnicas, estos juegos simulaban una vista 3D usando unos cuantos trucos que hacían que funcionaran en casi cualquier maquina. Los primeros y mas sencillos RPGs en primera persona dibujaban los pasillos de las mazmorras como lineas en perspectiva, creando la sensación de profundidad. Era un efecto que dejaba todo a la imaginación, pero tenia la ventaja que prácticamente cualquier maquina que tuviera gráficos lo podía manejar.

Un poco mas adelante, cuando las capacidades gráficas de los ordenadores y las técnicas de programación mejoraron, se empezó a utilizar un nuevo método que simulaba las paredes de los pasillos esta vez con todo detalle. El truco estaba en que el diseñador creaba, para cada tipo de pared, un gráfico desde todas las perspectivas posibles. Normalmente no eran muchas, de frente y de lado a 3 o 4 tamaños máximo. Y luego, dentro del juego, los colocaba siguiendo un mapa 2D, simulando la profundidad con los diferentes tamaños (grandes cerca, pequeños lejos). La técnica era bastante "espectacular" para la época y fue muy usada con juegos que están en la memoria de todos como los anteriormente mencionados.

 Pero también esta técnica tenia grandes defectos. Primero por que estaba limitado a un mapa 2D con paredes perpendiculares y segundo porque, al no poder haber transición entre un punto a otro del mapa, el movimiento era a saltos. Este movimiento brusco era bastante confuso hasta que te acostumbrabas, y muy desconcertante si tu no controlabas el personaje.

Con el tiempo este sistema callo en el olvido al ser remplazado primero por sistemas de ray casting (Legend of Valour, Elder Scrolls Arena como ejemplos primerizos) y mas adelante por engines 3D reales. Pero creo que en el proceso se perdió una parte de la magia y sencillez de estos primeros RPGs, que conseguían recrear un mundo 3D en cualquier maquina. No en vano aun hay juegos que intentan recuperar esta sistema junto con otros detalles retro, como Legend of Grimrock o Grimoire.

Pues bien, como un engine de este tipo es muy fácil de simular con un engine 3D actual, aquí tenéis un pequeño tutorial, con proyecto incluido, que muestra como crear vuestra vista en primera persona clásica en Unity 3D. Obviamente es solo una simulación, ya que los juegos originales utilizaban técnicas muy diferentes, pero es fácil crear una ambientación parecido.

Para el tutorial he utilizado texturas de alta calidad, pero nada os impide utilizar texturas mas retro para darle ese look vintage. También comentar que es necesario conocimientos básicos de como funciona Unity para poder seguirlo.

Espero vuestros comentarios!



Update con los links

No me había dado cuenta que con el vídeo empotrado es complicado que vierais los links que había en la información de youtube. Así que aquí los teneis:

El proyecto se puede descargar aquí
https://mega.co.nz/#!OB1WkRyC!DveNGEi...

(la demo se controla con los cursores)

El articulo en la Wiki de Unity sobre el movimiento en rejilla
http://wiki.unity3d.com/index.php/Gri...

Texturas usadas en la demo
http://opengameart.org/content/pietex...
http://opengameart.org/users/yughues

Y muchas mas arte libre en http://opengameart.org/

domingo, octubre 06, 2013

Making-of de "Tokyo Super Night"


Como sabéis Tokyo Super Night ya esta disponible tanto en iOS como en Android, así que para celebrarlo grabe un vídeo explicando como funciona la versión Android. Esta versión esta hecha con el sistema de desarrollo Unity 3D, sin usar ninguna extensión especial. No estoy seguro que sea de utilidad a nadie (demasiado técnico para gente que no conozca el mundillo, pero poco profundo para quienes sepan de que va esto de la creación de juegos), aunque si tenéis curiosidad en saber que hay detrás de un juego 2D sencillo, echadle un vistazo.

sábado, septiembre 07, 2013

¡La demo de Island of the Oracle 3D ya disponible!



Ya esta disponible la demo de este "remake" del RPG que hice en MSX, esta vez para Windows y Mac; en la forma de juego en primera persona con ray casting retro (ya sabéis, a lo Wolfenstein 3D).

Podéis descargarlo desde la página oficial. También tenéis un vídeo con los primeros momentos de la demo, que espero que sirva de ayuda para jugarla, aunque hay un mini-manual en la web. Si queréis saber como se hizo, hay mas información en este otro post y en los vídeos que fui haciendo en youtube.

Solo es un pequeño pedazo del juego, que seguro contiene bugs a montones y sin final (simplemente no puedes entrar a todas las areas), pero espero que os guste y estoy deseando saber vuestras opiniones.

Disclaimer: el ingles del juego es como algo "raro" XDD, no hagáis mucho caso a todas las faltas que hay (v.v)

miércoles, agosto 28, 2013

Unas palabras sobre mi RPG retro con raycasting

Los que me sigáis por otras redes sociales o youtube seguramente habréis visto la evolución de este proyecto mejor que los lectores de este humilde blog, ya que hasta ahora no me he decidido escribir una entrada especifica sobre este tema. Pero ya que estamos, vamos a empezar desde el principio y poner todo este proyecto en perspectiva.

Una de las primeras capturas, aun con los tiles del Wolfenstein
Como es habitual, todo empezó con un objetivo muchas mas sencillo, y algo diferente a un motor de ray casting. En realidad estaba intentando recrear en Flash un sistema de dungeons en primera persona como el de Eye of the Beholder, Dungeon Master y tantos otros clásicos de los 80 y 90. No tenia ninguna intención de crear un juego completo, solo una pequeña demo, ya que era solo un proyecto empezado en unas horas muertas que tenia a la semana. 

Arreglando la ocultacion de sprites al principio del proyeto

El problema con este tipo de engines es que, para hacerlo como en esa época, hacen falta los gráficos de las paredes dibujados en diferentes tamaños y perspectivas, algo que seguramente me llevaría mucho tiempo. Probé a usar 3D y simular un efecto similar con texturas, pero siempre se notaba el "truco" y quedaba demasiado moderno para mi gusto. 

Buscando métodos para darle un aspecto mas retro al proyecto (transformar las paredes con algún tipo de escalado sencillo) en alguna página se mencionaba que lo que hacían juegos como EoB se podía ver como un ray casting simplificado. Siempre había tenido interés en los engines de Id (creadores de Wolfenstein, Doom y demás joyas), y al ver aparecer esta palabra clave pensé en utilizar un sistema de ray casting para mi demo.

Probando a crear una interfaz después de decidirme a hacer un RPG
Después de estudiar otros sistemas de ray casting escrito para C, Flash y otros lenguajes decidí que era un proyecto no tan complicado y me puse manos a la obra. Hay mucha documentación y demos funcionales, así que no me costo mucho crear mi propio sistema y aparecieron los primeros muros (primero de colores planos y luego con las texturas del Wolfenstein 3D). Y bueno, para animar un poco la cosa me decidí también a implementar los sprites, lo que hizo que el escenario se llenara de caras sonrientes, el primer sprite.

Ahora los muros pueden ser dobles
Y la verdad, no recuerdo en que momento decidí utilizar este sencillo motor para hacer un juego, pero sucedió que en cierto momento me plantee que tipo de juego debía ser. Acabe pensando en hacer un pequeño RPG inspirado por los clásicos que había jugado a principios de los 90, como Legend of Valour o Drakhen.



Así que fui ampliando el engine, añadiendo un sistema de scripts, diálogos, eventos, inventario etc... Tal vez el proceso a partir de aquí esta mejor documentado por los audioboos y vídeos pertinentes en youtube.

Probando la iluminación de los escenarios
La cosa es que al decidir el contenido del juego pensé en realizar una versión en 3D del RPG que cree para MSX, y así nació "Island of the Oracle 3D". No es mas que un sencillisimo RPG, ya que prácticamente todo lo que puedes hacer ya se podía hacer en 8 bits y 24Kb.

El engine ya terminado
La primera parte del proyecto ya esta prácticamente terminada, así que en breve voy a publicar una demo jugable, estad atentos!

miércoles, julio 10, 2013

Version Android de "Dungeons of Diablet"


Cuando empece el proyecto de "Dungeons of Diablet" en ningún momento tenia pensado en realizar versión alguna fuera de los ordenadores domésticos. Pero durante el desarrollo ocurrió algo inesperado, Unity 3D, la plataforma de desarrollo que estaba utilizando empezaba a ofrecer también gratuitamente la opción de exportar para Android y iOS.

Dado que ya era gratis y mas que nada por curiosidad, a mitad del desarrollo probé a exportar el juego a Android, generando un fichero apk que raudo probé en mi Galaxy S3. Yo me esperaba que la cosa explotaría después del menú principal, o peor, no llegaría a arrancar. Nada mas alejado de la realidad, el juego funcionaba perfectamente, Unity simulaba que los toques a la pantalla táctil eran clicks de ratón y, exceptuando que alguna textura del terreno se veía cuadriculada, no había ningún problema. Incluso la velocidad era aceptable, a pesar de no haber sido optimizado ni siquiera en PC.

Bastante después de concluir la semana con Unity y por culpa de tener unos minutos sin nada que hacer delante del ordenador, me propuse a exportar, esta vez la versión final, a Android, a ver que tal quedaba. Estaba aun el problema del suelo a cuadros, pero seguía siendo totalmente jugable. El problema de las texturas parece que se debe a limitaciones de los dispositivos que utilizan Tegra (como mi S3) y solo tiene solución haciendo algunos trapicheos con el terreno. Y claro, también esta el problema que la jugabilidad esta pensada para que el jugador utilice un ratón.

Como la semana, mi tiempo limite, ya esta concluida, y el problema de las texturas no es fatal, me he decidido a publicar el juego tal cual para Android, para que cualquiera que tenga un rato libre lo pueda probar. Esta disponible en la pagina oficial del Dungeons of Diablet.

Si alguien lo prueba en su Android y le funciona (o no), estaría muy agradecido de escuchar que le parece.


lunes, junio 17, 2013

"Dungeons of Diablet" ya disponible!


Mi proyecto de crear un juego con Unity 3D en una semana ya esta terminado, y como prometí el juego ya esta disponible online, tanto en descarga (Mac y Windows) como para jugar directamente online (necesitas el plugin gratuito de Unity 3D).

Es un juego relativamente corto, en el vídeo podéis ver como me lo paso en 12 minutos (claro que yo me se de memoria los escenarios y donde están las llaves XD). Si tenéis un rato libre echarle un vistazo y contadme que os parece!

jueves, junio 13, 2013

Una semana con Unity: creando un clon de Gauntlet + Diablo (Día 7)



Por fin he podido acabar esta semana con Unity 3D (obviamente con días no consecutivos) y el juego ya esta listo para ser distribuido.

Durante este día solo he corregido bugs, balanceado la jugabilidad y añadido pequeños detalles como la música, así que no hay mucho que contar.

Todo los assets del juego son gratuitos de la Asset Store de Unity o bien de www.opengameart.org.

viernes, junio 07, 2013

Una semana con Unity: creando un clon de Gauntlet + Diablo (Día 6)



Esta vez me he centrado en hacer la experiencia de juego mas entretenida, nivelando el daño y mejorando la IA para que se disperse un poco y no te ataque en fila india. También he creado un par de niveles más.

Ya solo me queda un día más para terminar!

miércoles, mayo 29, 2013

Una semana con Unity: creando un clon de Gauntlet + Diablo (Día 5)



Con un poco de retraso ya tengo terminado mi quinto día de este proyecto con Unity.Esta vez me he dedicado a crear un nuevo nivel, esta vez ambientado en una mazmorra y a crear una iluminación mas oscura.

Para el siguiente día toca arreglar la AI y seguramente crear un nivel más.

martes, mayo 21, 2013

Una semana con Unity: creando un clon de Gauntlet + Diablo (Día 4)



Hoy ya tenemos la estructura de juego, es decir un menú principal para iniciar el juego, el juego en si y cuando mueres una pantalla de "Game Over" para volver a empezar.
A parte también hay puertas, a lo Gauntlet, que necesitan de llaves para abrirse. También he corregido algún que otro bug no demasiado visible pero que estaba ahí, dando la lata.

jueves, mayo 16, 2013

Una semana con Unity: creando un clon de Gauntlet + Diablo (Día 3)



En este tercer día he añadido efectos de sonido (aunque aun no están todos), items que se pueden recoger y una interfaz de usuario básica. También he mejorado algunos detalles, como el arma que lanzamos o el cursor en el el suelo.

martes, mayo 14, 2013

Una semana con Unity: creando un clon de Gauntlet + Diablo (Día 2)


En este segundo día ya se pueden ver las mecánica básica del juego: enemigos que salen de generadores y que pueden ser destruidos apuntándolos con el ratón  A parte, el jugador ha dejado de ser un cubo para convertirse en un "rey espartano" de la Asset Store de Unity.

lunes, mayo 13, 2013

Una semana con Unity: creando un clon de Gauntlet + Diablo (Día 1)



El resultado las primeras 8 horas de mi proyecto de crear un clon de Gauntlent con jugabilidad a lo diablo en Unity. Los objetivos eran crear un escenario con cámara isométrica y un jugador que se mueve con el ratón  Aunque el jugador solo es un cubo, complete los objetivos dentro del tiempo limite.

martes, mayo 07, 2013

Una semana con Unity: Creando un clon de Gauntlet + Diablo

Aunque ya hacia un tiempo que estaba trapicheando con Unity me he decidido ha aprender a utilizarlo en serio. Y para ello creo que no hay nada mejor que crear un juego completo, aprendiendo a la vez que se va necesitando.

Para que el proyecto no se eternice, he decidido que el proyecto debe ocupar una semana. O para ser exactos 7 días x 8 horas al día. Como mis tareas diarias me impiden estar 8 horas seguidas con este proyecto,  las horas no van a ser consecutivas y es muy probable que se extiendan por varios días. De todas formas, mi intención es finalizar esta aventura en menos de un mes.

Y que tipo de juego voy a crear? Pues, pensándolo un poco, me he decidido por un clon de Gauntlet (con sus niveles, salidas múltiples y generadores de enemigos), pero con un control con el ratón a lo Diablo. Creo que este tipo de juego es lo suficientemente sencillo para crearlo en este tiempo pero a la vez tiene la complejidad para suponer un pequeño reto.

Mas o menos este es plan de acción:

Día 1

  • Un nivel de prueba
  • Cámara isométrica (mas o menos)
  • Control del jugador con el ratón

Día 2

  • Generadores de enemigos
  • Enemigos que persiguen al jugador
  • Ataque sencillo del jugador

Día 3

  • Interfaz de usuario
  • Efectos de sonido
  • Ataque de enemigos
  • Items (vida, oro y llaves)

Día 4

  • Ciclo de juego (pantalla de inicio - juego - game over - inicio)
  • Puertas
  • Salidas y conexiones entre niveles

Día 5 

  • Añadir niveles y enemigos

Día 6

  • IA de enemigos
  • Potenciadores de arma
  • Mas niveles

Día 7

  • Pulir el juego, arreglar bugs
  • Reserva de tiempo para tareas retrasadas 

Para realizar este proyecto solo me voy a servir de assets gratuitos, tanto de la Assets Store de Unity como de opengameart.org. Me parece que para crear un juego de este tipo hay material gratuito mas que suficiente (aunque mas adelante ya me planteare si hago una versión DX con material de pago para que sea mas vistoso).

Finalmente, a la hora de escribir esto ya he terminado los dos primeros días  y estoy empezando el tercero, así que pronto publicare un vídeo con el progreso que voy haciendo.

Actualización

martes, abril 16, 2013

Añadir acciones personalizadas en ArmA 3



Como añadir acciones personalizadas (las que se activan con la rueda del ratón) programando con el lenguaje de script de ArmA 3.