Source: http://docplayer.es/2700204-Windows-linux-programacion-de-videojuegos-introduccion-ejecutar-los-videojuegos-introduccion-ejecutar-los-videojuegos.html
Timestamp: 2018-05-26 16:41:56+00:00

Document:
Windows. Linux. Programación de Videojuegos Introducción Ejecutar los videojuegos. Introducción: Ejecutar los videojuegos - PDF
Windows. Linux. Programación de Videojuegos Introducción Ejecutar los videojuegos. Introducción: Ejecutar los videojuegos
Download "Windows. Linux. Programación de Videojuegos Introducción Ejecutar los videojuegos. Introducción: Ejecutar los videojuegos"
Inés San Segundo Escobar
1 Introducción Ejecutar los videojuegos Introducción: Ejecutar los videojuegos Windows La forma más sencilla de ejecutar un videojuego programado con Bennu en Windows es a partir de su fichero de código con extensión.prg Con el Bennupack instalado, los ficheros.prg se abren automáticamente con Notepad++, el entorno de programación que además usaremos para programar nuestros videojuegos. Con el fichero.prg, abierto en Notepad++ pulsamos la tecla F6, esto abrirá una ventana del sistema en la se realizará una verificación de que el código es correcto y no tiene errores, esta tarea se denomina compilación. Si la compilación es correcta, se generará un fichero.dcb y se ejecutará el videojuego, en caso contrario tendremos que solucionar el problema de compilación modificando el código del videojuego. Todos los videojuegos de ejemplo asociados a cada tema del tutorial compilarán y se ejecutarán sin problemas. Linux Para ejecutar un videojuego programado con Bennu en Linux tendremos que abrir una terminal. Con el paquete de Bennu para Linux instalado, en la terminal introduciremos en primer lugar el comando bgdc seguido de la ruta del fichero.prg que queremos compilar. Si la compilación es correcta, se generará un fichero.dcb, y deberemos introducir el comando bgdi seguido de la ruta del fichero.dcb generado para ejecutar el videojuego. Tanto en Linux como en Windows no habrá problemas de compilación para ejecutar los videojuegos de ejemplo. Será cuando editemos nuestro propio código o modifiquemos el de los videojuegos existentes cuando empezaremos a encontrarnos con los primeros errores de compilación. A lo largo de este tutorial aprenderemos a utilizar el lenguaje de programación BennuGD y solucionar los problemas de compilación que pronto nos encontraremos durante nuestra experiencia como programadores. Introducción Ejecutar los videojuegos Pág. 1
2 Tema 1 Gráficos I 1. Gráficos I Si vamos a programar un videojuego, lo primero que vamos a necesitar son los gráficos. Podríamos empezar con simples dibujos hechos a mano con Paint o cualquier otro programa básico de dibujo, pero ya que vamos a dedicar varias horas de trabajo a nuestro videojuego, es mejor que seleccionemos unos gráficos atractivos, que pueden ser por ejemplo nuestros personajes favoritos o los escenarios de aquél videojuego con el que pasamos cientos de horas jugando años atrás. En primer lugar crea una carpeta personal donde guardar tu trabajo, vamos a aprender a seleccionar gráficos. 1.1 Sprites Un spriteset es una tabla de gráficos con todas las animaciones de un determinado personaje: Tendrás que elegir varios spritesets. Puedes encontrar una amplia colección en internet, ya sea por ejemplo en webs como o simplemente buscando en Google Imágenes con las palabras claves sprite y ripped, esta última palabra significa extraído de un videojuego. También puedes buscar en el DVD de recursos de la actividad, en la sección Biblioteca GFX. Imagen 1: Ejemplo de spriteset Al seleccionar nuestros spritesets debemos tener en cuenta: Perspectiva Animaciones Resolución Lateral, superior o isométrica. Es recomendable comenzar con spritesets en perspectiva lateral. Nuestro personaje NO podrá realizar más acciones que las que tiene su spriteset. El tamaño en píxeles de cada animación (Sprite) es una buena indicación de la calidad del spriteset. Observa que en la Imagen 1, tenemos un spriteset de perspectiva isométrica, sin animación de salto y con una resolución media, ni muy alta como pudiera ser la de Street Fighter II ni muy baja como pudiera ser la del primer Super Mario Bros. Tema 1 Gráficos I Pág. 1
3 Tema 1 Gráficos I 1.2 Backgrounds Un background es el gráfico del escenario donde transcurrirá la acción de nuestro videojuego. Selecciona varios backgrounds. Nuevamente podrás encontrarlos en webs como en Google Imágenes con las palabras clave scroll o background, y también ripped. Y de la misma forma también encontrarás muchos en el DVD de recursos de la actividad, en la Biblioteca GFX, en la sección de Scrolls, fondos y escenarios. Al igual que los spritesets, los backgrounds también pueden tener perspectiva lateral, superior o isométrica. Selecciona backgrounds con la misma perspectiva que tus spritesets. Recuerda que, como ya hemos dicho, es mejor comenzar con un videojuego en perspectiva lateral. En cuanto a la resolución, evita backgrounds con una Imagen 2: Ejemplo de bakground resolución demasiado pequeña (Inferior a 320x240 píxeles) porque probablemente no lleguen a cubrir la pantalla, y evita también resoluciones demasiado grandes (Superiores a 4096x4096 píxeles) porque consumiremos muchos recursos y ralentizaremos el PC, tanto a la hora de trabajar con ellos como a la hora de moverlos dentro de nuestro videojuego. En el peor caso podremos escalar el tamaño de los backgrounds, pero es algo que tenderemos a evitar por ahora. Observa que los backgrounds y los sprites son algo totalmente separado. En ocasiones nos encontraremos con backgrounds que conservan algunos elementos como enemigos o items. Éstos se denominan backgrounds sucios, ya que probablemente tengamos que terminar limpiando esas impurezas antes de incluirlos en nuestro videojuego. Observa que en la Imagen 2, tenemos un background de perspectiva superior, con una resolución algo baja, y que podemos considerar sucio si nuestra idea es que esos arbustos puedan ser cortados. Tema 1 Gráficos I Pág. 2
4 Tema 2 Gráficos II 2. Gráficos II En el tema anterior hicimos una cuidadosa selección de gráficos para nuestro videojuego. Ahora vamos a trabajar con ellos para dejarlos listos para ser incluidos en un videojuego. 2.1 Recorte de spritesets Cada spriteset almacena una gran cantidad de animaciones (Sprites) distintas. Lo primero que tenemos que hacer es recortarlas para dejar cada sprite en un archivo de imagen distinto. Es algo que podríamos hacer con Paint, seleccionando un rectángulo, copiándolo, pegándolo en un archivo nuevo... Pero esa sería una tarea demasiado costosa, es por eso que haremos uso de un programa específico para esta tarea de recorte: Castle Split Image. Este programa nos permite dividir cualquier imagen en filas y columnas, tantas como queramos, de manera que pulsando después un botón el programa se encarga de generar todos los recortes del spriteset, cada uno en un archivo distinto. Observa que en el Dibujo 1 hemos usado 2 reglas verticales para separar las animaciones, es aconsejable que cada regla quede lo más cercana posible a la animación, lo ideal sería por ejemplo a 1 pixel de distancia. Imagen 1: Reglas horizontales y verticales en Castle Split Image Debes observar que cada spriteset tiene un color de fondo distinto y en general muy contrastado. Cuando terminemos de recortar lo próximo que haremos será eliminar ese color de fondo, y para poder hacerlo es imprescindible que todos los sprites que generemos tengan formato de archivo.png. Otros formatos como.bmp,.jpg, etc. no nos servirán, así que establece el formato.png como el formato de corte en el menú File/Preferences... de Castle Split Image. Salvo excepciones, un spriteset siempre está ordenado por filas. Por esa razón, cada vez que trazamos una línea vertical observaremos que amputamos partes de los sprites superiores e inferiores. Por esta razón tendremos que trabajar cada vez una fila del spriteset, guardando los resultados de cada corte en una carpeta distinta. Cada vez que recortamos generamos una cierta cantidad de recortes no válidos que tendremos que ir borrando. Esto es sencillo si activamos las Vistas en Miniatura en el menú Ver de la carpeta en la que residen los cortes Si has seguido estos pasos cuidadosamente, ya puedes ir al menú File/Generate Images... para generar todos los sprites. Tema 2 Gráficos II Pág. 1
5 Tema 2 Gráficos II 2.2 Eliminar el color de fondo Para poder hacerlo es imprescindible que hayas generado los cortes en formato.png. Estás a tiempo de asegurarte, ya que si no están en ese formato todo lo que hagas de aquí en adelante no servirá de nada. Para eliminar el color de fondo usaremos Paint.NET, un programa con decenas de funcionalidades que iremos viendo poco a poco, aunque por ahora nos bastará con una de ellas: La herramienta Varita Mágica. Imagen 2: Varita mágica en Paint.NET La varita mágica permite seleccionar una zona de color uniforme haciendo clic sobre un color de la imagen, podemos eliminar esa zona pulsando la tecla Supr. Sólo queremos eliminar el color de fondo, así que configuraremos la Tolerancia a 0% para evitar que seleccione otros colores similares. Verás la barra de tolerancia en la parte central superior del programa. Ten en cuenta que en ocasiones el color de fondo no está contiguo, sería el caso de un gráfico en forma de donut, cuyo centro también tendrá el color de fondo. Para evitar tener que hacer 2 (O más) veces el mismo proceso, podemos configurar la saturación en modo global haciendo clic en el icono en forma de Relámpago, que pasará a tomar forma de Planeta indicando que se seleccionará todo el color en toda la imagen. Debes eliminar el color de fondo en todos y cada uno de tus recortes. Puedes agilizar mucho esta tarea si seleccionas todos tus recortes y los arrastras al lienzo de Paint.NET. El programa los abrirá todos a la vez y podrás trabajar mucho más rápido. Cuando hayas terminado, en lugar de guardar uno por uno los recortes, puedes cerrar directamente el programa y te avisará de si quieres guardar todo el trabajo. Las tareas de recorte de gráficos y de eliminación del color de fondo son bastante monótonas, pero son imprescindibles si queremos hacer un videojuego 100% personalizado por nosotros. Es recomendable recortar los spritesets completamente así como eliminar el color de fondo de todos los recortes, así no tendremos que volver a repetir esta tarea. Tema 2 Gráficos II Pág. 2
6 Tema 2 Gráficos II 2.3 Crear un fichero para gráficos (FPG) Todos los gráficos que vamos a usar en nuestro videojuego deben estar almacenados en un fichero de extensión FPG, en el que se guardan asignándoles un número distinto a cada uno. Para realizar esta tarea usaremos el programa FPG Edit. FPG Edit tiene una sección superior en la que podemos navegar por nuestras carpetas buscando nuestros gráficos, mientras que en la sección inferior tenemos las imágenes que contiene nuestro FPG, con un número asociado en lugar de su nombre de archivo original. Un botón verde con forma de flecha (Add) nos permite añadir nuevas imágenes, cuyo número podemos indicar modificando el valor que hay a la derecha de la barra central del programa y pulsando a continuación el botón '#' que hay a su lado. Imagen 3: Interfaz del programa FPG Edit Podemos numerar los gráficos de nuestro videojuego como queramos, pero para llevar un orden y evitar confusiones al seguir este curso, es aconsejable que sigas la siguiente numeración: Número en el FPG Del 1 al 200 Del 201 al 400 Del 401 al 600 Del 601 al 800 Del 801 al 999 Gráficos a guardar Protagonista/s de nuestro videojuego. Disparos, hechizos e items. Scrolls, escenarios y fondos. Enemigos u otros personajes. Elementos decorativos y otros elementos. Tema 2 Gráficos II Pág. 3
7 Tema 3 Introducción al lenguaje de programación Bennu 3. Introducción al lenguaje de programación Bennu En el tema anterior construimos un fichero FPG con todos los gráficos que vamos a utilizar en nuestro videojuego. Ya estamos listos para comenzar a hacer uso de él y empezar a ver en pantalla nuestros gráficos. 3.1 Concepto de lenguaje de programación Un lenguaje de programación consiste en una serie de palabras clave que, correctamente asociadas y ordenadas, nos permiten dialogar con el procesador expresando el comportamiento que queremos obtener para nuestro programa o videojuego. El lenguaje Bennu posee una gran cantidad de palabras clave, con distinta utilidad, potencia y complejidad, que iremos introduciendo poco a poco durante este tutorial. Si es la primera vez que te encuentras con un lenguaje de programación debes saber que en general son una mezcla entre la lengua inglesa y las matemáticas. No te dejes intimidar por su aparente complejidad, seguro que vas a disfrutar mucho utilizándolo. 3.2 Concepto de proceso en Bennu Existen muchos tipos de lenguajes de programación. Java es un lenguaje orientado a objetos, C es un lenguaje imperativo, Bennu en cuestión es un poco especial, según la teoría de lenguajes de programación puede considerarse un lenguaje orientado al proceso. Para hacernos una idea, todo elemento que haya en pantalla es un proceso: Nuestro protagonista, cada disparo, cada enemigo... El lenguaje nos permite definir el comportamiento de un proceso, por ejemplo el de un disparo, y éste puede ser invocado tantas veces como queramos de una manera tan sencilla como es escribir su nombre. Es algo que veremos a fondo en los siguientes temas, por ahora vamos a trabajar a fondo con un único proceso, que definiremos como queramos, y que será invocado tan sólo 1 vez. Tema 3 Introducción al lenguaje de programación Bennu Pág. 1
8 Tema 3 Introducción al lenguaje de programación Bennu 3.3 Aspectos básicos de un proceso en Bennu Todo proceso en Bennu tiene una serie de aspectos que determinan cómo lo visualizaremos en la pantalla, o incluso si estará visible en la pantalla o fuera de ella. A continuación vamos a enumerar los aspectos básicos de un proceso en Bennu. Todos los aspectos tienen un determinado valor numérico. Te darás cuenta de que con ellos y con nuestro FPG tenemos lo suficiente para modelar prácticamente cualquier comportamiento que hayas visto en cualquier videojuego comercial en 2 dimensiones. Aspecto graph x y size Funcionamiento Es el aspecto fundamental de un proceso. Es el número de gráfico del FPG que nuestro proceso utilizará para mostrarse en pantalla. Por ejemplo, si hacemos que graph valga 201 y ese número corresponde al gráfico de un misil en nuestro FPG, entonces nuestro proceso se mostrará en pantalla con el aspecto de ese misil. Si no le decimos a nuestro proceso cuál es su valor de graph, entonces graph valdrá 0 y el proceso será invisible. Sirve para determinar la posición de un proceso en pantalla. Generalmente la pantalla tiene una resolución de 640x480 píxeles, aunque Bennu nos permitirá cambiarla más adelante. El valor de x es el píxel, medido desde el extremo izquierdo de la pantalla, en el que se mostrará el proceso. Por ejemplo, si hacemos que x valga 320, entonces el proceso se mostrará en el centro de la pantalla horizontalmente. Si no le decimos a nuestro proceso cuál es su valor de x, entonces x valdrá 0 y el proceso aparecerá en el extremo izquierdo de la pantalla. De forma similar a x, sirve para determinar la posición de un proceso en pantalla. El valor de y es el píxel, medido desde la parte superior de la pantalla, en el que se mostrará el proceso. Por ejemplo, si hacemos que y valga 240, entonces el proceso se mostrará en el centro de la pantalla verticalmente. Si no le decimos a nuestro proceso cuál es su valor de y, entonces y valdrá 0 y el proceso aparecerá en el extremo superior de la pantalla. Determina cuál es el tamaño con el que se dibujará el proceso en pantalla. Observa que la pantalla tiene una cierta resolución en píxeles y cada gráfico del FPG un cierto tamaño en píxeles. El valor de size indica en tanto por ciento (%) el tamaño con el que veremos el gráfico en pantalla. Por ejemplo, si hacemos que size valga 200 y el graph del proceso tiene un tamaño de 20x20 píxeles, entonces el proceso se dibujará en pantalla con un tamaño de 40x40 píxeles, un 200% más grande que su tamaño original. Si no le decimos a nuestro proceso cuál es el valor de size, entonces size valdrá 100 y el proceso se dibujará con el tamaño original de su gráfico. Tema 3 Introducción al lenguaje de programación Bennu Pág. 2
9 Tema 3 Introducción al lenguaje de programación Bennu angle Indica cuál es el ángulo de giro con el que se dibujará el proceso en pantalla. Gracias a este aspecto, con un único gráfico de un balón podremos hacer que éste gire. El valor de angle indica en milésimas de grado la inclinación con la que se dibujará el gráfico en pantalla. Por ejemplo si hacemos que angle valga el proceso se verá girado 180 grados, boca abajo. Si no le decimos a nuestro proceso cuál es su valor de angle, entonces angle vale 0 y el proceso se dibujará normalmente. La razón por la cual angle se mide en milésimas de grado es para permitir giros con mucha precisión, sobre todo en gráficos grandes, como pudiera ser un escenario. 3.4 Aspectos avanzados de un proceso en Bennu A continuación una serie de aspectos de un proceso que no utilizaremos por el momento, pero que nos permitirán más adelante programar comportamientos más complejos de una manera mucho más cómoda. Aspecto flags z Funcionamiento Este aspecto avanzado permite que el proceso sea dibujado aplicando distintos efectos gráficos. Su valor numérico no tiene ninguna unidad de medida, simplemente cada número ofrece un efecto distinto y hay que consultar esta tabla para conocer su funcionamiento. Valores posibles de flags son: 0 para dibujado normal, 1 para dibujar el gráfico espejado horizontalmente, 2 para dibujar el gráfico espejado verticalmente, 4 para dibujar el gráfico con una transparencia del 50%, 8 para dibujar el gráfico con una transparencia del 90%, y el resto los probaremos más adelante, en general no se usan los flags a partir del 8. Los valores de flags corresponden a potencias de 2, esto permite que puedan sumarse entre ellos obteniendo la aplicación de todos los valores sumados. Por ejemplo si hacemos que flags valga 7 estaremos aplicando 1+2+4, y el proceso se dibujará espejado horizontalmente, espejado verticalmente y además con una transparencia del 50%. Si no indicamos cuál es el valor de flags, entonces flags vale 0 y el proceso se dibuja normalmente. Este aspecto avanzado es útil cuando tenemos una gran cantidad de procesos distintos en pantalla. En esos casos observaremos que unos procesos son dibujados por encima o por debajo de otros, y no siempre obtendremos el orden de dibujado esperado. El valor de z indica la profundidad de dibujado, de forma que procesos con valores mayores de z se dibujarán por debajo de los procesos con menores valores de z. Por ejemplo si a nuestro proceso protagonista le damos un valor de z que vale 1 y a un proceso aura situado sobre el protagonista le damos un valor de z que vale 2, entonces veremos el aura detrás de nuestro protagonista. Sin embargo si intercambiamos los valores de z veremos el aura por delante de nuestro protagonista, ocultando su gráfico. Si no especificamos el valor de z, entonces z vale 0 y los procesos se dibujan con el orden que decida el procesador. Tema 3 Introducción al lenguaje de programación Bennu Pág. 3
10 Tema 3 Introducción al lenguaje de programación Bennu Aspecto ctype Funcionamiento Este aspecto avanzado es útil cuando tenemos un escenario o scroll cuyo tamaño en píxeles es superior a la resolución en píxeles de la pantalla. En ese caso el scroll no cabe en la pantalla y sólo podemos ver una determinada zona del scroll cada vez. Si esto sucede, es probable que nos interese que los aspectos básicos x,y de nuestro proceso no tengan como origen la esquina superior izquierda de la pantalla, sino que tengan como origen la esquina superior izquierda del escenario o scroll. Si no especificamos el valor de ctype, entonces ctype vale 0 y las coordenadas x,y tienen como origen la esquina superior izquierda de la pantalla. En cambio si hacemos que ctype valga 1, entonces las coordenadas x,y tienen como origen la esquina superior izquierda de nuestro scroll. 3.5 Ejercicio teórico: Los aspectos de un proceso Bennu en un videojuego comercial Piensa en Galaxian, un sencillo arcade de los años 80, e intenta adivinar el posible valor de los aspectos de proceso en Bennu que corresponderían para cada uno de los elementos que muestra en pantalla. Piensa después en The Legend of Zelda, un RPG más complejo desarrollado para SNES en los años 90, e imagina cómo cambiarían los valores de los aspectos, especialmente los avanzados como ctype, que facilitaría calcular las coordenadas x,y de los diferentes procesos que recorren el escenario o que se mantienen fijos en pantalla. Imagen 1: Galaxian, un arcade de los años 80 Imagen 2: The Legend of Zelda, un RPG de los años 90 Tema 3 Introducción al lenguaje de programación Bennu Pág. 4
11 Tema 4 El lenguaje: Asignaciones 4. El lenguaje: Asignaciones En el tema anterior explicamos los aspectos básicos de cualquier proceso gráfico en Bennu. Estos eran: Aspectos básicos graph Su número de gráfico dentro del fichero.fpg que creamos en las primeras sesiones. x,y Su posición horizontal y vertical medida en pixels respecto de la esquina superior izquierda de la pantalla. size Su tamaño medido en % respecto del tamaño original de su graph (Por defecto 100). angle Su ángulo medido en milésimas de grado (Por defecto 0). Aspectos avanzados flags Efectos visuales (0 = Normal, 1 = Espejo horizontal, 2 = Espejo vertical, 4 = Transparencia 50%, etc.) ctype Indica si las coordenadas x,y son relativas a la pantalla o al scroll (Valores 0 ó 1 respectivamente). z Indica la profundidad de dibujado, que indica si un proceso se dibuja por encima o por debajo de otro. file Especifica el fichero.fpg en el que se buscará el graph (Sólo cuando usemos múltiples ficheros.fpg). 4.1 Definición de asignación Una asignación establece un valor numérico a cualquiera de los aspectos de un proceso. Su sintaxis es la siguiente: Aspecto = Valor; //Es importante no olvidar el símbolo ';' (Un punto y coma) que indica el fin de la asignación. A continuación añadiremos las siguientes asignaciones entre las etiquetas BEGIN y del proceso principal de nuestro videojuego y comprobaremos que el funcionamiento es exactamente el indicado en la tabla anterior. graph=1; x=100; y=200; size=50; angle=90000; El proceso toma el gráfico número 1 de nuestro fichero.fpg. Posiciona el proceso a 100 pixels del lateral izquierdo de la pantalla. Posiciona el proceso a 200 pixels de la parte superior de la pantalla. Cambia el tamaño del proceso a un 50% de su tamaño original. El proceso se muestra rotado 90 grados (Recuerda que angle se mide en milésimas de grado). Tema 4 El lenguaje: Asignaciones Pág. 1
12 Tema 4 El lenguaje: Asignaciones 4.2 Primeras pruebas con nuestro videojuego Bennu En la carpeta Videojuego que lleva asociada este tema, encontrarás un programa tan sencillo que no puede considerarse un videojuego, pero que nos servirá para realizar todas las pruebas iniciales y será la base para el videojuego que crearemos a medida que avancemos en este tutorial. El contenido de la carpeta es el siguiente: DLL images videojuego.prg Ejecutar en Windows.bat Ejecutar en Linux.sh videojuego.dcb En esta carpeta se encuentra toda la maquinaria (Archivos DLL) que hace que nuestro videojuego pueda ejecutarse. Por el momento no tocaremos nada de esa carpeta. En esta carpeta se guarda el/los ficheros para gráficos (FPG) del videojuego. Por ahora trabajaremos con el FPG que tiene y en el próximo tema lo sustituiremos por el nuestro. Este archivo contiene el código fuente que editaremos para añadir nuevas instrucciones. Podrías editarlo perfectamente con el Bloc de Notas, aunque si instalas la utilidad Bennupack podrás editarlo con el programa Notepad++, que resulta mucho más cómodo de utilizar e incluye algunas otras utilidades interesantes. Comprueba errores en el código (Ésto se llama compilar) y si todo es correcto ejecuta el videojuego. Lo mismo que lo anterior, pero funciona en el sistema operativo Linux. Este fichero se genera a partir del código cuando compilamos, y es lo que realmente se ejecuta. Ya estás listo para hacer las pruebas propuestas en este tema y otras que se te puedan ocurrir. No olvides guardar el archivo.prg cada vez que modifiques el código, no olvides asegurarte de que el resultado de la compilación no muestra errores, y durante tus primeros pasos como programador, no olvides que las instrucciones deben terminarse con un ';'. Los errores anteriores serán el 99% de tus posibles problemas a la hora de empezar a programar, el resto los iremos viendo más adelante. Tema 4 El lenguaje: Asignaciones Pág. 2
13 Tema 5 El lenguaje: Incrementos 5. El lenguaje: Incrementos En el tema anterior establecimos valores numéricos fijos a los diferentes aspectos de un proceso. La asignación de valores fijos no es suficiente para poder crear nuestro videojuego, así que ahora aprenderemos a hacer que esos aspectos se modifiquen automáticamente durante la ejecución gracias a las instrucciones de incremento. 5.1 Definición de incremento Una incremento establece una variación sobre cualquiera de los aspectos de un proceso a partir de una operación matemática que generalmente es muy sencilla, por ejemplo una suma. Su sintaxis es la siguiente: Aspecto = Aspecto + Valor; //Una vez más, no olvides el ';' (Punto y coma). Prueba a añadir las siguientes asignaciones entre las etiquetas LOOP y del proceso protagonista de tu videojuego y comprueba que el incremento da resultado. graph=graph+1; x=x+4; y=y-1; size=size+2; angle=angle-1000; El proceso toma el siguiente número de gráfico del fichero.fpg cada vez que se muestra en pantalla. El proceso se desplaza 4 píxeles hacia la derecha cada vez que se muestra en pantalla. El proceso sube 1 píxel cada vez que se muestra en pantalla. El proceso aumenta en un 2% su tamaño cada vez que se muestra en pantalla. El proceso rota 1 grado en sentido antihorario cada vez que se muestra en pantalla. 5.2 Aclaraciones sobre las asignaciones y los incrementos Tanto las asignaciones como los incrementos son instrucciones, y por tanto siempre deben situarse entre las etiquetas BEGIN y, que indican el principio y el final de la zona de instrucciones que ejecuta un proceso. Los procesos tiene un único bloque de instrucciones BEGIN, y para facilitar su ubicación, la etiqueta BEGIN se tabula exactamente a la misma altura que la etiqueta que la cierra. Dentro del bloque BEGIN, justo al final del mismo, encontraremos un bloque LOOP. Las instrucciones que vienen antes del bloque LOOP se ejecutan una única vez al iniciar el proceso y suelen ser asignaciones, mientras que las instrucciones dentro del LOOP se ejecutan todo el tiempo y suelen ser incrementos. Tema 5 El lenguaje: Incrementos Pág. 1
14 Tema 5 El lenguaje: Incrementos 5.3 Ejercicio: Uso de los aspectos básicos de un proceso Con lo aprendido hasta ahora ya deberías saber hacer que tu proceso protagonista aparezca inicialmente en la esquina superior izquierda de la pantalla, y se desplace hasta la esquina inferior derecha al tiempo que gira y aumenta de tamaño. Truco: La proporción de pantalla en píxeles es 4:3, por tanto avanzando 4 píxeles en horizontal (Eje X) y 3 píxeles en vertical (Eje Y) debería recorrer exactamente la diagonal de la pantalla. Ejemplos de resolución de pantalla que cumplen la proporción 4:3 son 640x480, 800x600 y 1024x768. Estas resoluciones pueden establecerse modificando los valores de la instrucción set_mode(800,600,16,mode_window); que encontrarás en el primer BEGIN del código de tu videojuego. 5.4 Ejercicio: Uso de los aspectos avanzados de un proceso El aspecto flags de un proceso produce efectos visuales muy interesantes. Aprovechando lo aprendido sobre incrementos puedes hacer que tu proceso incremente en 1 el valor de su variable flags con la instrucción: flags=flags+1; De esta forma podremos ver la totalidad de los efectos visuales que podremos aplicar modificando esta variable. Truco: Los diferentes flags son apilables, esto significa que cuando flags vale 5 estamos aplicando flags=1 (Espejo horizontal) y flags=4 (Transparencia 50%) al mismo tiempo, puesto que 1+4=5. Otro ejemplo más complejo sería cuando flags vale 209, que aplicaría los flags y cuyo efecto sería bastante extraño... En general no usaremos flags más allá del 16. Tema 5 El lenguaje: Incrementos Pág. 2
15 Tema 6 El lenguaje: Condiciones 6. El lenguaje: Condiciones En el tema anterior establecimos incrementos en los aspectos del proceso principal de nuestro videojuego logrando que su gráfico, su posición, su tamaño, etc. Variasen durante la ejecución. El uso de instrucciones de incremento ofrecen dinamismo en el videojuego, pero el comportamiento que obtenemos siempre es el mismo y no hay ningún tipo de interacción. Para lograr interacción y un resultado mucho más sofisticado debemos hacer uso de las condiciones. 6.1 Definición de condición Su nombre exacto es condicional. Consiste en establecer una condición, de manera que, sólo cuando ésta se cumpla se ejecutarán una o más instrucciones, que pueden ser asignaciones, incrementos o incluso otras condiciones. Los condicionales son algo que utilizaremos extensivamente durante toda nuestra vida como programadores, así que es conveniente que te quede totalmente claro su funcionamiento. Su sintaxis es la siguiente: IF (<condición>) <Asignaciones, incrementos u otras condiciones, cada una en una línea> Observa que hemos encerrado entre <> la condición sin explicar su sintaxis exacta. Esto se debe a que puede haber una gran diversidad de ellas. Vamos a ver unas cuantas en este tema, y más adelante veremos una descripción más formal de todas las condiciones que podemos llegar a usar. key(_right) Se cumple cuando se pulsa la tecla direccional derecha (_right) del teclado. Podemos sustituir _right por cualquier otra tecla direccional, cualquier letra o número, _enter, _space, etc. El nombre de la tecla siempre va precedido por el carácter '_'. x<0 Se cumple cuando el aspecto x (La posición horizontal en píxeles) del proceso tiene un valor menor que 0. Esto ocurre cuando el proceso se sale por la izquierda de la pantalla. y>600 Se cumple cuando el aspecto y (La posición vertical en píxeles) del proceso tiene un valor mayor que 600. Esto ocurre cuando el proceso se sale por la parte inferior de la pantalla. Siempre y cuando estemos ejecutando con una resolución de pantalla de 800x600 píxeles. graph==9 Se cumple cuando el aspecto graph (El número de gráfico del FPG) del proceso tiene un valor exactamente igual a 9. Esta condición nos permite por ejemplo detectar cuándo termina una animación. Observa que se usan 2 símbolos '=' para comprobar (leer), y 1 símbolo '=' para asignar (escribir). Tema 6 El lenguaje: Condiciones Pág. 1
16 Tema 6 El lenguaje: Condiciones 6.2 Instrucciones a ejecutar cuando se cumple una determinada condición Vamos a ver unos cuantos ejemplos típicos de uso de las condiciones: IF (x>800) x=0; IF (key(_down)) y=y+4; IF (key(_right)) graph=graph+1; IF (graph>9) graph=1; Cuando el aspecto x del proceso tiene un valor mayor que 800 píxeles (Se sale por la derecha de la pantalla), se le asigna un 0 a su aspecto x para hacer que vuelva a aparecer por la izquierda. Cuando se pulsa la tecla direccional abajo, el proceso incrementa su aspecto y en 4, bajando 4 píxeles cada vez. Serviría para desplazar nuestro proceso por la pantalla. Cuando se pulsa la tecla direccional derecha, el proceso incrementa su gráfico en 1 (Recorre 1 a 1 los gráficos del FPG y por tanto se anima). Si además de pulsar la tecla direccional derecha el valor de graph se hace mayor que 9, volvemos a asignar el graph 1, logrando así que el proceso utilice la animación cuyos gráficos van del 1 al 9. Ten en cuenta que las nuevas instrucciones condicionales que estamos añadiendo pueden entrar en conflicto con incrementos o asignaciones anteriores que pudiera haber en nuestro proceso. Asegúrate de que entiendes lo que ocurrirá cuando añadas nuevas instrucciones, y si notas algún comportamiento extraño, no dudes en borrar todas las instrucciones y volver a empezar. 6.3 Ejercicio: Programar los controles de un juego de naves Con las indicaciones dadas en los ejemplos anteriores ya deberías ser capaz de añadir las condiciones necesarias en el proceso principal de tu videojuego para que se mueva hacia arriba, abajo, izquierda y derecha con las teclas direccionales correspondientes. Además puedes programarlo de manera que, si el proceso se sale por arriba, por abajo, por la izquierda o por la derecha de la pantalla, vuelva a aparecer por el lado opuesto. No te compliques demasiado programando la animación, ya que es un tema más complejo de lo que parece a simple vista y lo veremos con detenimiento más adelante. Tema 6 El lenguaje: Condiciones Pág. 2
17 Tema 7 Procesos I 7. Procesos I Ya hemos modificado el proceso principal de nuestro videojuego y hemos practicado con él las instrucciones fundamentales para modificar los aspectos de un proceso en Bennu. En el punto 3.2 de este temario comentamos que era posible definir el comportamiento de un proceso y a continuación poderlo invocar tantas veces como queramos. Hasta ahora sólo hemos modificado el proceso principal de nuestro videojuego. Hemos definido cual era su comportamiento, y no hemos tenido necesidad de invocarlo porque el proceso principal se invoca siempre (Y una sola vez.) cuando ejecutamos el videojuego. 7.1 Definir un proceso en Bennu Vamos a definir un proceso. Sus instrucciones serán exactamente las mismas que habíamos incluido en el proceso principal de nuestro videojuego, la diferencia es que ahora podemos darle un nombre, el que nosotros queramos, por ejemplo protagonista. La sintaxis de un proceso en Bennu es la siguiente: PROCESS <Nombre del proceso> ( ) BEGIN <Asignaciones iniciales> LOOP <Asignaciones, incrementos y condiciones a ejecutar siempre> FRAME; Después del del proceso principal (Al final del código), podemos añadir todas las definiciones de proceso que queramos, aunque por ahora sólo vamos a añadir una. Observa que el nombre del proceso debe ir seguido de los caracteres ( ), un paréntesis de apertura y uno de cierre que pronto veremos para qué sirven. Entre las etiquetas BEGIN y iran las instrucciones que determinan el comportamiento del proceso. Puedes cortar directamente todas las instrucciones entre el BEGIN que tenías en el proceso principal de tu videojuego y pegarlas aquí, a excepción de las instrucciones set_mode(); y load_fpg(); que sólo se deben ejecutar al principio para configurar el modo de vídeo y cargar el archivo FPG con los gráficos, respectivamente. Tema 7 Procesos I Pág. 1
18 Tema 7 Procesos I 7,2 Invocar un proceso en Bennu Si has definido correctamente el proceso anterior, al compilar no deberías tener errores, pero al ejecutar es probable que no veas nada en pantalla. Esto se debe a que todavía no has invocado el proceso, y tu videojuego no hace nada más que establecer el modo de vídeo con set_mode();, cargar el archivo FPG con load_fpg(); y terminar. Para invocar un proceso basta con escribir su nombre, es lo que haremos después de cargar el archivo FPG. Si nuestro proceso se llamaba protagonista, entonces la invocación tendría la siguiente sintaxis: protagonista ( ) ; Observa nuevamente que la invocación también incorpora los caracteres ( ), y además un ';' al final, como las instrucciones de asignación e incremento que vimos en los temas anteriores. Antes de seguir adelante, si no consigues resultados, recuerda que cada tema lleva asociado un videojuego donde puedes comprobar el código correcto. Si tienes algún problema lo más probable es que te hayas dejado alguna de las etiquetas, que sirven para indicar el fin de los bloques de código que abren las etiquetas BEGIN, LOOP e IF, entre otras. 7.3 Ejercicio: Invocar un proceso disparo Una vez hayas conseguido crear tu proceso Bennu correctamente, vamos a hacer la prueba de crear otro proceso adicional que será el disparo de nuestro protagonista. Lo llamaremos disparo (Por ejemplo.), y su definición se encontrará justo después del último del proceso protagonista. Puedes darle las asignaciones iniciales que creas convenientes, por ahora no te preocupes por su posición inicial ya que más adelante aprenderemos a hacer que los disparos aparezcan en la posición exacta donde se encuentra el protagonista. El disparo debe tener necesariamente un bloque LOOP donde se incluyan los incrementos necesarios para desplazarlo por la pantalla. Además, antes del, deberemos tener una instrucción FRAME;, esto generalmente se cumplirá para todos los procesos dentro de su bloque LOOP, ya que de lo contrario no mostrarán nada en pantalla, e incluso haremos que el videojuego se quede bloqueado. Más adelante explicaremos la instrucción FRAME; en profundidad. Para invocar el disparo añadiremos el siguiente condicional dentro del bloque LOOP del protagonista: IF ( key(_space) ) disparo ( ) ; Tema 7 Procesos I Pág. 2
19 Tema 8 Procesos II 8. Procesos II Ya hemos aprendido lo más básico para definir e invocar nuevos procesos. Es importante que en este punto tengas bien clara la diferencia entre definir un proceso e invocarlo: Definir un proceso: Consiste en escribir todo su código en un bloque PROCESS -. Sólo se hace una vez. El proceso no aparece en pantalla hasta que sea invocado.. Invocar un proceso: Consiste en escribir su nombre seguido de ( ); Podemos hacerlo tantas veces como queramos. Hace que el proceso aparezca en pantalla. Si has realizado correctamente el programa del tema anterior, habrás comprobado que el proceso disparo no era capaz de ser invocado en la misma coordenada x,y en la que se encontraba el protagonista. En este tema vamos a ver una sencilla forma de lograr esto. 8.1 Jerarquía de procesos en Bennu Ahora que distinguimos entre definir e invocar un proceso, podemos comenzar con uno de los aspectos más avanzados del lenguaje Bennu. Se trata de la jerarquía de procesos, y es que todos los procesos en Bennu se organizan exactamente igual que un árbol genealógico. El padre que gobierna toda la jerarquía de procesos es el proceso principal, ése que está definido dentro del primer bloque BEGIN y que por ahora se encarga de ejecutar las instrucciones set_mode(); y load_fpg();. El proceso protagonista era invocado dentro del BEGIN del proceso principal, por tanto podemos decir que el protagonista es hijo del proceso principal, y obviamente, que el proceso principal es el padre del protagonista. Finalmente el proceso disparo era invocado dentro del BEGIN del proceso protagonista, por tanto decimos que el proceso disparo es hijo del proceso protagonista, y de la misma manera, el proceso protagonista es padre del proceso disparo. Proceso principal Proceso protagonista Proceso disparo Tema 8 Procesos II Pág. 1
20 Tema 8 Procesos II 8.2 Herencia de procesos en Bennu Apoyándose en la jerarquía de procesos, Bennu nos ofrece un mecanismo muy sencillo para hacer que ciertos procesos puedan heredar aspectos (Como graph, x, y, size, etc.) de sus padres. Esto nos servirá para, por ejemplo, hacer que el proceso disparo herede la coordenada x, y de su padre (El protagonista) y así lograr que los disparos nos ofrezcan la sensación correcta, apareciendo siempre en la posición del protagonista, sea cual sea. Para ello usaremos uno de los aspectos más avanzados de un proceso Bennu. Se trata de un aspecto llamado father, que mediante el operador '.' nos permite acceder a los aspectos básicos del proceso padre según esta table: father.graph father.x father.y Indica el número de gráfico en el archivo FPG de nuestro proceso padre. Indica la posición horizonal en píxeles de nuestro proceso padre. Indica la posición vertical en píxeles de nuestro proceso padre y lo mismo con father.size, father.angle, father.flags, etc. Para hacer que el disparo herede la coordenada x, y de su padre (El protagonista) al ser invocado, podemos usar la asignación, asignando a su x el valor de father.x y asignando a su y el valor de father.y. Estas instrucciones estarían dentro del bloque BEGIN del proceso disparo, antes del bloque LOOP, ya que nos interesa que la herencia sólo se realice una vez nada más ser invocado el disparo. PROCESS disparo() //Definición del proceso disparo: BEGIN //Inicio de las instrucciones del proceso x=father.x; //Asignamos la x del padre y=father.y; //Asignamos la y del padre graph=45; //Asignamos el gráfico que queramos LOOP //A partir de aquí repetimos siempre x=x+10; //Incrementamos la x en 10 FRAME; //Mostramos resultado en la pantalla //Fin de la repetición //Fin de las instrucciones del proceso Además de father, podemos acceder a la jerarquía en otras direcciones utilizando son (El último hijo de un proceso), smallbro (El hermano anterior de un proceso) y bigbro (El siguiente hermano de un proceso). También podríamos acceder a un abuelo utilizando father.father, pero no es necesario complicarse, ya que en la práctica nos bastará con usar father solamente. Tema 8 Procesos II Pág. 2
21 Tema 9 Prácticas 9. Prácticas Es un buen momento para hacer un uso más avanzado de todos los conceptos que hemos visto sobre el lenguaje Bennu. El interés principal de este tema no es introducir conceptos nuevos, sino más bien aprovechar lo que ya sabemos para mejorar ciertos aspectos de nuestro videojuego, especialmente el apartado de animación. Como única novedad explicaremos algunos usos más avanzado de los condicionales. 9.1 Condicionales con varias alternativas En ocasiones puede interesarnos crear un condicional en el que se evalúen varias condiciones, pero sólo se ejecuten las instrucciones asociadas a la primera que se cumpla, ignorando las siguientes. El ejemplo más sencillo es el caso de las teclas direccionales izquierda y derecha. Vamos a utilizar los condicionales de manera que, cuando se pulsen ambas teclas a la vez, nuestro videojuego interprete sólo una. Para ello podemos utilizar un condicional múltiple, cuya sintaxis es la siguiente: IF (<condición 1>) <instrucciones 1> ELSIF (<condición 2>) <instrucciones 2> ELSIF ELSE <instrucciones N> //Primera condición a evaluar //Ejecutaremos esto si se cumple //Segunda condición a evaluar //Ejecutaremos esto si se cumple //Siguientes condiciones a evaluar... //Si no se cumple ninguna de las anteriores condiciones //Ejecutaremos esto //Fin del condicional múltiple Es número de ELSIF que sirven como alternativas a la primera condición es ilimitado, podemos poner tantos como queramos. También es importante que entiendas que todas las condiciones se evalúan por orden, y una vez se cumple la primera de ellas, se ejecutan sus instrucciones asociadas y se sale del condicional múltiple. Esto quiere decir que sólo se interpreta como máximo una condición. Y finalmente debes saber que es posible tener un condicional múltiple con ELSE pero sin ningún ELSIF o bien con uno o más ELSIF pero sin el último ELSE. Tema 9 Prácticas Pág. 1
22 Tema 9 Prácticas 9.2 Ejercicio: Aplicar todo lo anterior a nuestro videojuego Gracias a todo lo que hemos visto hasta ahora en este temario, debemos ser capaces de lograr que nuestro protagonista sea capaz de mirar a izquierda y a derecha (Modificando su aspecto flags) cuando pulsamos la tecla correspondiente. También deberíamos poder conseguir que se anime, utilizando su animación de andar. Con el disparo ocurre lo mismo, deberíamos ser capaces de lograr que los disparos avancen en la dirección a la que mira nuestro protagonista (Nuevamente gracias al aspecto flags). También deberían poder animarse con su animación correspondiente. Aplica todo esto a tu videojuego. Si tienes dudas puedes mirar el videojuego de ejemplo de este tema. Sobre todo evita copiar y pegar las instrucciones del videojuego de ejemplo en tu videojuego. Aunque resulta tentador, en general no trae más que problemas, ya que el objetivo no es hacer que el videojuego funcione correctamente, sino que tú entiendas cómo hacer que el videojuego funcione correctamente. Tema 9 Prácticas Pág. 2
23 Tema 10 Un Matamarcianos 10. Un Matamarcianos Si has completado con éxito el reto del tema anterior ya estas preparado para realizar tu primer videojuego jugable. Gracias a la generación de números aleatorios de Bennu, su sistema de detección de colisiones entre procesos y unas breves nociones sobre destrucción (Formalmente muerte) de procesos, dotaremos a nuestro videojuego de todo lo necesario para ser un matamarcianos de los años Introducción a la generación de números aleatorios en Bennu La generación de números aleatorios es un aspecto básico en cualquier videojuego para garantizar que el resultado de la ejecución no sea siempre el mismo. En nuestro caso vamos utilizar los números aleatorios para crear un proceso enemigo capaz de moverse aleatoriamente en los ejes x, y de manera que su movimiento sea siempre impredecible. La sintaxis de la generación de un número aleatorio es la siguiente: rand ( <valor_mínimo>, <valor_máximo> ); Donde valor_mínimo y valor_máximo son los valores numéricos del intervalo dentro del que será generado el número aleatorio. Unos ejemplos de aplicación de los números aleatorios serían los siguientes: Rand ( 1, 100 ); x = x + rand ( -4, 4 ); IF ( rand ( 0, 1 ) == 0 ) x = x + 4; Devuelve un valor aleatorio entre 1 y 100. Es el ejemplo más sencillo, pero utilizada por sí sola esta instrucción no tiene ningún efecto. El proceso modifica su posición en el eje x una cantidad aleatoria de píxeles comprendida entre -4 y 4. El proceso ejecuta la instrucción x = x + 4; una de cada dos veces. Es como tirar una moneda al aire, y si sale cara, realizar una acción. Con estas nociones crea un nuevo proceso llamado enemigo, con lo que has aprendido hasta ahora puedes echarle imaginación o bien puedes consultar el enemigo en el videojuego de ejemplo asociado a este tema. Tema 10 Un Matamarcianos Pág. 1
24 Tema 10 Un Matamarcianos 10.2 Introducción a la muerte de procesos en Bennu Existen varias formas de matar a un proceso en Bennu, aunque vamos a ver la más sencilla de todas. Generalmente nos interesará que un proceso muera cuando se cumpla una determinada condición. Dado que nuestros enemigos son capaces de moverse libre y aleatoriamente por la pantalla, vamos a proponer un ejemplo de muerte muy sencillo: Si uno de los enemigos sale fuera de los límites de pantalla, entonces morirá. Con esto evitaremos que los enemigos salgan de pantalla y se vayan hasta el infinito, ya que si se diese ese caso estarían consumiendo memoria y recursos del PC innecesariamente. Para matar a los enemigos haremos que utilicen la instrucción BREAK; La instrucción BREAK; no mata directamente al proceso, pero hace que éste abandone su bloque LOOP-, y como después del LOOP- no hay más instrucciones el proceso deja de ejecutar instrucciones y muere. Es una forma relativamente sencilla y limpia de matar procesos. El código a añadir en nuestro enemigo, dentro de su bloque LOOP-, sería el siguiente: IF ( x < 0 ) BREAK; ELSIF ( x > 800 ) BREAK; ELSIF ( y < 0 ) BREAK; ELSIF ( y > 600 ) BREAK; //Si sale de la pantalla por la izquierda //Abandona el LOOP y muere //Si sale de la pantalla por la derecha //Abandona el LOOP y muere //Si sale de la pantalla por arriba //Abandona el LOOP y muere //Si sale de la pantalla por abajo //Abandona el LOOP y muere //Fin de las condiciones Otra forma que ofrece Bennu para conseguir el mismo resultado sería la siguiente, haciendo uso de los operadores lógicos, en este caso OR, que sirve para activar una condición cuando se cumpla una cualquiera de sus subcondiciones : IF ( ( x < 0 ) OR ( x > 800 ) OR ( y < 0 ) OR ( y > 800 ) ) BREAK; De la misma forma que OR, podemso usar el operador lógico AND, que serviría para activar una condición cuando se cumplan t todas sus subcondiciones. Aunque es algo que ya iremos viendo a medida que avance el temario. Tema 10 Un Matamarcianos Pág. 2
25 Tema 10 Un Matamarcianos 10.3 Detección de colisiones entre procesos El funcionamiento de nuestro matamarcianos será así de sencillo: Si un enemigo colisiona con nuestro protagonista, entonces nuestro protagonista morirá. Si un enemigo colisiona con un disparo, entonces el enemigo morirá. Para ello haremos uso de la función collision(); cuya sintaxis es la siguiente: collision ( type <nombre_del_proceso> ) La expresión anterior activará un condicional si el proceso que la ejecuta está colisionando en pantalla con cualquier proceso del tipo dado por <nombre_del_proceso>. Por ejemplo, para que los enemigos mueran al colisionar con un proceso de tipo disparo deberían ejecutar el siguiente código dentro de su bloque LOOP-: IF ( collision ( type disparo ) ) BREAK; 10.4 Generación aleatoria de enemigos Hemos definido el proceso enemigo, pero no lo hemos invocado. De momento haremos que sea el protagonista quien genere aleatoriamente enemigos en el escenario, no es la mejor solución pero sí la más sencilla. Para ello el protagonista debería ejecutar las siguientes instrucciones: IF ( rand ( 1, 10 ) == 1 ) //Si un dado de 10 caras saca como resultado 1 enemigo ( ) ; //Invocamos un enemigo //Fin del condicional Y para que los enemigos aparezcan aleatoriamente en las esquinas de la pantalla podemos añadir estas instrucciones iniciales, antes de su bloque LOOP-: x = rand ( 0, 1 ) * 800; //Su posición x podrá valer o bien 0 o bien 800 y = rand ( 0, 1 ) * 600; //Su posición y podrá valer o bien 0 o bien 600 Nota que el carácter '*' (Asterisco) es el signo de multiplicación en Bennu. Tema 10 Un Matamarcianos Pág. 3
26 Tema 11 Variables I 11. Variables I Has aprendido a crear un matamarcianos y ya deberías tener base suficiente como para explotar tu imaginación y añadir otros elementos como explosiones, distintos enemigos, incluso un segundo protagonista para que se trate de un juego para 2 jugadores, siempre que cuentes con los gráficos necesarios. Pero todavía nos queda muchísimo por descubrir del lenguaje Bennu. En este tema vamos a aprender a tratar conceptos un poco más abstractos de un videojuego, generalmente valores numéricos diversos como pueden ser la puntuación o los puntos de vida de un determinado proceso Concepto de variable Una variable es un pedazo de la memoria de nuestro PC en el que podemos almacenar un valor, generalmente numérico, aunque más adelante veremos otras posibilidades. El ejemplo más claro son los aspectos básicos de un proceso en Bennu como graph, size, etc. No son más que variables, simples números que se almacenan en la memoria de nuestro PC y a los que podemos hacer referencia con su nombre. Todos los aspectos básicos de un proceso en Bennu que hemos visto hasta ahora son útiles para crear un videojuego básico, pero no nos permiten recrear aspectos más complejos como la puntuación o los puntos de vida. Para ello necesitaremos crear nuevas variables, como veremos a continuación Ámbito de una variable Como ya hemos dicho, una variable puede almacenar datos como la puntuación o los puntos de vida. Es importante que observes que se trata de valores que se comportarán de manera muy distinta si tenemos en cuenta que la puntuación es un valor único, mientras que cada enemigo puede tener un valor de vida distinto... Tema 11 Variables I Pág. 1
27 Tema 11 Variables I Para salvar estas dificultades se utiliza el ámbito de las variables, que por ahora distinguiremos entre global o privado, según la siguiente definición: GLOBAL: Una variable tiene este ámbito cuando almacena un valor único y común para todos los procesos del videojuego. El caso más claro es la puntuación del juego, ya que hay sólo una zona de memoria donde se almacena ese dato. PRIVATE: Una variable tiene este ámbito cuando almacena un valor que puede ser distinto para distintos procesos. El caso más claro son los puntos de vida, ya que puede haber varios enemigos y cada uno tendrá una zona de memoria donde almacenar su valor de vida. Este concepto nos permitirá inventar nuevas variables a las que podremos dar el nombre y los valores iniciales que queramos Variables GLOBAL Las variables GLOBAL se incluyen en la zona de código que se sitúa al principio del programa, justo debajo de la sentencia PROGRAM y antes de la primera sentencia BEGIN. Por ejemplo, para añadir una variable encargada de almacenar la puntuación, que tenga un valor inicial 0, nuestro programa quedaría así: PROGRAM videojuego; INCLUDE "DLL\import.prg"; //Incluye las DLL necesarias GLOBAL BEGIN puntos=0;... set_mode(800,600,32,mode_window); //Establecemos el modo de vídeo Tema 11 Variables I Pág. 2
28 Tema 11 Variables I Una vez incluida una variable GLOBAL, cualquier proceso es capaz de modificar su valor como si se tratase de cualquiera de sus aspectos básicos. Ejemplos de uso de la variable GLOBAL puntos serían los siguientes: Puntos=100; puntos=puntos+1; IF (puntos>1000) BREAK; Asigna el valor 100 a la variable puntos. Suma 1 al valor de la variable puntos. Si la variable puntos almacena un valor mayor que 100 el proceso muere Variables PRIVATE Las variables PRIVATE se incluyen en la zona de código entre el PROCESS que encabeza la declaración de un proceso y el BEGIN que indica el comienzo de sus instrucciones. Por ejemplo, para añadir una variable encargada de almacenar un valor de 100 en la vida inicial de cada enemigo, nuestro proceso enemigo quedaría así: PROCESS enemigo(); PRIVATE vida=100; BEGIN Una vez incluida una variable PRIVATE, cada proceso es capaz de modificar su valor como si se tratase de cualquiera de sus aspectos básicos, siendo posible que distintos procesos conserven distintos valores. Ejemplos de uso de la variable PRIVATE puntos serían los siguientes: vida=100; vida=vida-1; IF (vida<=0) BREAK; Asigna el valor 100 a la variable vida del proceso. Suma 1 al valor de la variable vida del proceso. Si la variable vida del proceso almacena un valor menor o igual que 0 el proceso muere. Tema 11 Variables I Pág. 3
29 Tema 11 Variables I 11.5 Aplicando GLOBAL y PRIVATE Crea la variable GLOBAL que almacena la puntuación y la variable PRIVATE que almacena la vida de cada proceso enemigo. Haz el uso adecuado de estas variables para conseguir que los enemigos sean capaces de resistir 10 golpes antes de morir, y que antes de morir sumen 1 a la puntuación. Un ejemplo básico de enemigo que haga uso de las variables sería: PROCESS enemigo(); PRIVATE vida=10; BEGIN LOOP... IF ( collision (type disparo) ) vida = vida -1; IF ( vida <= 0 ) puntos = puntos + 1; BREAK;... FRAME; No olvides crear la variable puntos en la sección GLOBAL, el hecho de crear una nueva variable se denomina formalmente declarar, y en adelante hablaremos de declarar nuevas variables, ya sean GLOBAL o PRIVATE cuando sea necesario. Observarás que, a pesar de tener 10 puntos de vida, los enemigos mueren demasiado rápido... Esto se debe a que detectan la colisión durante varios FRAMES, y en cada uno de ellos restan vida puesto que es lo que hemos impuesto. Más adelante veremos cómo resolver ese tipo de problemas. Tema 11 Variables I Pág. 4
30 Tema 12 Variables II 12. Variables II Ya sabes cómo declarar nuevas variables en tu videojuego, pero todavía tenemos muchísimo que aprender sobre ellas y sus aplicaciones. Habrás observado que el comportamiento de tus enemigos no tiene demasiado sentido, ya que aparecen en las esquinas de la pantalla y su movimiento aleatorio no suele ser capaz de hacerlos llegar al centro de la misma. En este tema vamos a hacer uso de las variables para conseguir que los enemigos vayan siempre al centro de la pantalla Una variable tiene el significado que nosotros queramos darle Todos los aspectos básicos de un proceso en Bennu como pueden ser graph, size o angle tienen un significado concreto: Indican su número de gráfico dentro del FPG, su tamaño en tanto por ciento, su ángulo en milésimas de grado, etc. En cambio las nuevas variables que creamos no tienen un significado por sí mismas sino que debemos ser nosotros, a través del código, los que les demos un significado concreto, por ejemplo haciendo que sucedan determinadas cosas cuando una de las variables que hemos declarado tome un determinado valor. Recuerda que en el tema anterior hemos declarado la variable PRIVATE vida y nos ha servido para lograr que los enemigos sean capaces de resistir varios golpes antes de morir... Observa que mediante el lenguaje Bennu cada vez nos resulta más fácil expresar comportamientos más y más complejos. Ahora vamos a crear una nueva variable PRIVATE que llamaremos dirección (Sin acento), y nos servirá para indicar dónde aparecerá cada nuevo enemigo y hacia dónde debe moverse. Por qué la dirección es PRIVATE y no GLOBAL? Pues porque cada enemigo podrá tener una dirección distinta, recuerda que el ámbito GLOBAL sólo nos sirve para declarar un valor que resulte único para todos los procesos del videojuego. Tema 12 Variables II Pág. 1
31 Tema 12 Variables II 12.2 Ejemplo del significado que le podemos dar a una variable Haciendo uso de la función rand(), vamos a hacer que la nueva variable PRIVATE direccion de nuestro enemigo tome un valor inicial aleatorio entre 1 y 4 antes de entrar en el bloque LOOP-. Consultando el valor obtenido, el enemigo decidirá su posición inicial y la dirección hacia la que se debe mover, según la siguiente tabla: direccion == 1 direccion == 2 direccion == 3 direccion == 4 El enemigo aparece en la esquina superior izquierda y debe moverse hacia la esquina inferior derecha. El enemigo aparece en la esquina superior derecha y debe moverse hacia la esquina inferior izquierda. El enemigo aparece en la esquina inferior derecha y debe moverse hacia la esquina superior izquierda. El enemigo aparece en la esquina inferior izquierda y debe moverse hacia la esquina superior derecha. Para aplicar este concepto, el código del enemigo deberá cambiar ligeramente a la hora de decidir su posición inicial (Antes del bloque LOOP-) así como deberá modificar su comportamiento al desplazarse por la pantalla (Dentro del bloque LOOP- ). Tema 12 Variables II Pág. 2
32 Tema 12 Variables II Un ejemplo de utilización de la variable dirección sería el siguiente: PROCESS enemigo() PRIVATE //Datos privados de cada proceso enemigo vida=10; //vida con un valor inicial de 10 dirección; BEGIN graph=50; direccion=rand(1,4); //Toma un valor de dirección aleatorio entre 1 y 4 IF ( direccion == 1 ) //Condición: Si la dirección es 1 x = 0; //Nos posicionamos arriba a la izquierda y = 0; ELSIF ( direccion == 2 ) //Alternativa: Si la dirección es 2 x=800; //Nos posicionamos arriba a la derecha y=0; ELSIF ( direccion == 3 ) //Alternativa: Si la direccion es 3 x=800; //Nos posicionamos abajo a la derecha y=600; ELSIF ( direccion == 4 ) //Alternativa: Si la dirección es 4 x=0; y=600; //Nos posicionamos abajo a la izquierda Tema 12 Variables II Pág. 3
33 Tema 12 Variables II LOOP IF ( direccion == 1 ) //Condición: Si la dirección es 1 x = x + 4; //Nos desplazamos hacia abajo a la derecha y = y + 4; ELSIF ( direccion == 2 ) //Alternativa: Si la dirección es 2 x = x - 4; //Nos desplazamos hacia abajo a la izquierda y = y + 4; ELSIF ( direccion == 3 ) //Alternativa: Si la dirección es 3 x = x - 4; //Nos desplazamos hacia arriba a la izquierda y = y - 4; ELSIF ( direccion == 4 ) //Alternativa: Si la dirección es 4 x = x + 4; //Nos desplazamos hacia arriba a la derecha y = y - 4; FRAME; Tema 12 Variables II Pág. 4
34 Tema 13 Textos I 13. Textos I Hasta ahora hemos aprendido a mostrar procesos gráficos por pantalla y a modificar su comportamiento cambiando los valores de sus variables. Un videojuego tiene otros elementos además de los procesos gráficos, uno de los más importantes son los textos que se muestran por pantalla, ya que entre otras cosas, nos permiten ver los valores que almacenan algunas variables en cada momento: El número de gráfico, la posición, los puntos de vida... En este tema aprenderemos a escribir textos básicos en pantalla de una forma muy sencilla Fuente de texto La fuente de texto es el tipo de letra que se utilizara para imprimir por pantalla los textos de nuestro videojuego. Lo primero que vamos a necesitar es diseñar nuestra propia fuente de texto. Es muy sencillo si utilizamos el programa FNT Edit, incluido en el Bennupack. Este programa nos permite seleccionar cualquiera de las fuentes del sistema, como por ejemplo Arial, Verdana u otras que hayamos instalado. Nos permite seleccionar el tamaño de la fuente, su color, su tipo y color de sombra y su tipo y color de borde, permitiendo así diseñar prácticamente cualquier tipo de letra, bien sea para un pequeño marcador de puntuación o para el título de presentación del videojuego. Tema 13 Textos I Pág. 1

References: Resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución