Llegamos al quinto capítulo del curso de iniciación a Lua, en el comenzaremos la programación creando nuestra escena de entrada. Por la extensión he dividido este capítulo en dos entregas.

Comenzamos la programación de nuestro juego creando el que será nuestro primer archivo de código Lua. Recordad que para crear un fichero con este formato podíamos o renombrar un archivo con extensión “.txt” o guardarlo directamente con esa extensión desde el editor de textos.

La primera parte de nuestro juego, que además nos servirá como toma de contacto con la programación en lua, será una sencilla escena de entrada que muestre nuestro logo desplazándolo desde la derecha y un texto estático. Usaremos tan sólo un archivo de imagen que será el logo a mostrar.

Comenzaremos el proceso analizando la variables que precisamos. Tan sólo necesitamos almacenar la posición de la imagen y la propia imagen, además podemos declarar el texto estático o almacenarlo dentro dentro del argumento de la función. Puesto que una serie de atributos hacen referencia a un mismo elemento que es la imagen, los declararemos en una tabla.

Una tabla o array es una conjunto de variables ordenadas e identificadas dentro de la misma mediante un índice o sufijo. Esta explicación es un poco abstracta por lo que la ilustraremos con un ejemplo: almacenar un serie de números y acceder a ellos. Para empezar declararemos un array, su estructura es similar a la de la variable, pero todo lo que está contenido en ella se declara entre barras quebradas “{}” y separado por comas:

Numero = {1,4,2,7,9}

Para acceder a estos números deberíamos indicar el índice del mismo que se asigna considerando el primer número el 1 y así sucesivamente. Este índice debe estar inicado entre cochetes “[]” que seguiran al nombre de la tabla. Así sabemos:

Numero[1] = = 1

Numero[2] = = 4

..

Numero[5] = = 9

NOTA: No confundir el operador boleano de igualación “= =” con el de asignación “=”.

La importancia de las tablas va más allá de almacenar valores, ya que esto mismo lo puede hacer una variable, nos abren las puertas a métodos de programación más potentes, a un mayor orden y a iteraciones sobre datos complejas y eficientes. Por lo tanto, su uso será muy habitual y casi obligado.

Volviendo a nuestra escena de entrada, necesitamos un array para los elementos de nuestra imagen. En este caso declararemos una tabla de forma que sus elementos sean identificados por un sufijo, ya que de esta forma podemos identificar nemotecnicamente a que dato accedemos. Para realizar este proceso seguiremos esta estructura:

Logo = {x = 0, y = 150, Img = Image.load(“img/logo.png”)Logo.x == 0

Logo.y == 80

Como podéis ver declaramos un array, y dentro los valores son declarados como variables, es decir, con un nombre identificativo. Este nombre será el sufijo que usaremos para acceder a ella dentro de la tabla, tal y como vemos a continuación de la declaración. Si nos fijamos en los valores que almacenamos en la tabla, vemos un valor x que almacena la posición en el eje de la x, una variable y que realiza lo propio en el eje y, y por último Img que almacena la imágen.

Los valores de las coordenadas definen la posición en pantalla del logo. El eje x marca la posición en una recta imaginaria dividida en píxeles que se extiende a lo ancho. El eje y, también pero define la posición a lo alto. Observad que tan sólo usamos dos coordenadas por que trabajamos en 2 dimensiones, por lo tanto en nuestro sistema geométrico definido por dos ejes (dimensiones) tan sólo necesitamos dos valores para definir un punto. Debemos tener en cuenta que en el punto definido por estas dos variables será donde empiece a dibujarse la imagen desde la esquina superior izquierda y que el origen de valores de los dos ejes se establece tal y como se muestra en la figura:

Otra peculiaridad que observamos y que nos permitirá introducir la carga de imágenes, es el valor Logo.Img = Image.load(“ruta”). Evidentemente a esta variable le hemos asignado el valor de una función, Image.load(“ruta”) que se encarga de cargar una imagen y devolverla como valor de retorno. No entraremos en detalles sobre el valor de retorno hasta que hablemos de la declaración de funciones, pero debemos saber que esto tiene como resultado final que la variable almacene la imagen cargada.

Debemos tener cuidado con el número de imágenes cargadas ya que estas se almacenan en variables, que a su vez se alojan en la memoria ram y esta es limitada, si se termina e intentamos seguir escribiendo nuestro programa fallará. Como último comentario de esta función, especificaremos que tan sólo puede cargar imágenes en formato png y jpeg, y que como hemos dicho deben ser almacenadas en variables para poder ser mostradas por pantalla posteriormente.

Imagen = Image.load(“ruta/nombreachivo.png”)

Imagen = Image.load(“ruta/nombreachivo.jpg”)

Ya estamos listos para pasar a nuestra estructura principal para la escena de entrada. Estableceremos una condición especifica para que esté en nuestra escena de entrada mediante la introducción de una primera variable de un grupo que nos dará información sobre el estado del juego que almacenaremos en una tabla de nombre Juego.

Juego = {Estado = 0}

Estableceremos que mientras que estado sea igual a 0, nos encontraremos en la escena de entrada. El hecho de que usemos una iteración finita, en lugar de una infinita, para esta parte se debe a que no es el juego propiamente dicho y así evitamos declarar dos bucles que siempre se cumplan. En el próximo capítulo veremos como declarar un bucle así.

Por tanto, precisamos de un bucle while que dada una condición ejecuta aisladamente las tareas que tiene asignadas. Esto significa que mientras su condición se cumpla tan sólo se ejecutará el código que tiene definido, y no el resto del programa limitando el flujo de ejecución a su ámbito. En programación esta instrucción se engloba dentro del esquema iterativo junto con el for.

La certeza de la condición dada se evaluará mediante los operadores boleanos. Reciben este nombre debido a que devuelven exclusivamente un valor true o false valores que almacena una variable “boolean”. Son los siguientes:

==” Igual
>” Mayor
<” Menor
>=” Mayor o igual
<=” Menor o igual
~=” Diferente

NOTA: el carácter “~” se introduce pulsando ALT GR + 4 y espacio.

Ahora ya podemos definir nuestra condición para estar en la escena de entrada y de paso ver la estructura declaratoria de un bucle while:

Ahora ya podemos definir nuestra condición para estar en la escena de entrada y de paso ver la estructura declaratoria de un bucle while:

while Juego.Estado == 0 do

–Codigo

end

NOTA: El do no debe olvidarse ya que indica el final de la parte condicional y el inicio del código.

NOTA2: Tampoco debe olvidarse el end que marca el final del código.

Ya sólo nos queda mostrar la imagen, desplazarla por la pantalla e imprimir el texto estático. Para mostrar la imagen antes debemos realizar una serie de operaciones sobre la pantalla para dejarla lista. En primer lugar debemos borrarla, para que no se muestre lo que había anteriormente. Para ello usaremos la función screen:clear(Color), en caso de que no se de un color especifico usará el negro.

La pantalla está compuesta de dos caras que se alternan mediante la función screen.flip(). Cada vez que se ejecuta esta función se cambia la cara sobre la que se trabaja y la que se muestra. Así si al llamar a la función mostraremos la cara sobre la que hemos trabajado en esa iteración y la otra pasará a ser manipulada en la siguiente. Este concepto se entiende si pensamos en una pizarra en la que estamos situados por detrás del público, escribimos en una cara y giramos para que el público lo vea, escribimos en esa cara y giramos de nuevo… Evidentemente, nuestra máquina lo realizará a una velocidad muy grande.

Por último, debemos tener en cuenta un problema, que es que la pantalla no imprime entera de golpe, sino que va parte por parte hasta finaliza el proceso. Para evitar el antiestético efecto que produciría en nuestro juego Lua nos ofrece una función que espera a que toda la pantalla este volcada para mostrarla: screen.waitvBlankStart(miliseconds). El argumento lo dejaremos vacio si nuestra única intención es evitar el problema descrito.

Así ya tenemos la estructura básica de nuestro bucle en lo que se refiere a preparar a la pantalla para mostrar imágenes. La función screen:clear() irá primero, y al final del bucle tras haber finalizado las tareas pertinentes las que se encargan de terminar de mostrar la imagen:

while Juego.Estado == 0 do

screen:clear()

screen.flip()

screen.waitVblankStart()

end

Ya podemos realizar las operaciones para mostrar imágenes por pantalla. El método que se encarga de este proceso es screen:blit(coordenadax, coordenaday, imagen) que recibe tres argumentos como forma más simple para funcionar. El primero es la coordenada x, el segundo la coordenada y, y el tercero es una variable que contenga la imagen a mostar. Por tanto en nuestro caso la llamada a la función sería la siguiente:

screen:blit(Logo.x, Logo.y, Logo.Img)

Ya sólo nos falta el texto estático, para imprimirlo usaremos el método screen:print(x,y,texto,color). Lor argumentos x e y definen la posición en que se comenzará a imprimir el texto. Texto es una variable de tipo string o un string directamente definido sobre la función. Esto significa que:

Texto = “Este texto”

screen:print(20,20,Texto)

Imprimiría lo mismo que:

screen:print(20,20,”Este Texto”)

La principal diferencia está en el consumo de RAM, ya que de la segunda forma no podríamos reutilizar esa cadena de caracteres o string.

Un string es el tipo de variable que Lua define para almacenar texto y debe ir declarado entre comillas dobles <<“ ”>>. Hasta ahora no hemos hablado de los tipos de variable, pero los hemos usado. Hemos usado variables tipo número (las coordenadas) y tipo userdata (la imagen). Userdata es un tipo de variable que no está definido por lua sino por un módulo externo.

Por último el argumento color es una variable que almacena un color reconocible por el módulo de imagen. Para crear un color usamos el método Color.new(R,G.B) y los argumentos los valores dentro del sistema RGB.

Negro = Color.new(0,0,0)

Blanco = Color.new(255,255,255)

NOTA: consideraremos estos colores como declarados en nuestro código

Una vez añadidos los métodos para mostrar imagen y texto nuestra estructurá será algo parecido a esto:

while Juego.Estado == 0 do

screen:clear()

screen:blit(Logo.x, Logo.y, Logo.Img)

screen:print(20,240,”FMCDev”,Blanco)

screen:print(20,260,”http://fmcdev.es”,Blanco)

screen.flip()

screen.waitVblankStart()

end