Vistas de página en total

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

lunes, 19 de septiembre de 2016

Mi solución para juegos y aplicaciones

En las últimas entradas hemos estado viendo cómo resolver el problema de los distintos tipos de pantalla en los que nuestra aplicación se puede ejecutar. Hemos visto que Corona nos ofrece una pantalla virtual donde situamos nuestros objetos (con un tamaño definido por nosotros) y después Corona se encarga de escalar ese contenido a la pantalla real del dispositivo. Hemos visto que hay varios modos de escalado. Y además, sabemos que el API de Corona, en el objeto display tiene algunas constantes muy útiles. Con todo esto, y con la alineación de la pantalla virtual (que vamos a ver ahora mismo), es posible resolver casi cualquier problema. Nos centraremos en el modo "letterbox" que es el que yo utilizo habitualmente.
Empecemos con la alineación.

Alineación de la pantalla virtual

Como vimos, en modo "letterbox", el escalado puede producir bandas laterales (o superior/inferior) si las proporciones de la pantalla virtual no coinciden con las de la pantalla real. En estos casos Corona por defecto centra la pantalla virtual en la pantalla física, es decir, deja el mismo espacio arriba y abajo, o bien el mismo espacio a izquierda y derecha.
Sin embargo, este comportamiento por defecto se puede cambiar. Para ello, recurrimos al fichero config.lua:

application = {
    content = {
        width = 320,
        height = 480, 
        scale = "letterBox",
        xAlign = "center",
        yAlign = "center",
    },
}

Hemos añadido dos nuevos miembros a la conocida tabla application.content
xAlign indica la alineación horizontal
yAlign indica la alineación vertical
Con estos dos nuevos parámetros podemos cambiar la forma en que Corona sitúa la pantalla virtual dentro de la pantalla física.
El parámetro xAlign puede tomar los siguientes valores:
  • "left"
  • "center"
  • "right"
Y el parámetro yAlign puede tomar los siguientes valores:
  • "top"
  • "center"
  • "bottom"
De esta forma podemos controlar cómo se encaja la pantalla virtual en la física. En unos momento vamos a ver la utilidad de estos dos parámetros.

Solución para los juegos

Para los juegos, yo utilizo siempre el modo letterbox, para no perder información y para no deformar. Como van a aparecer bandas laterales en muchos casos, también utilizo xAlign = "center", yAlign="center" de esta forma me aseguro que el juego propiamente dicho aparece centrado en la pantalla.
¿Qué hago con las bandas laterales? Utilizo las constantes:

display.actualContentWidth
display.actualContentHeight

para poner un rectángulo o una imagen en el fondo que encaje bien con el resto del juego. Este rectángulo no aparecerá si las proporciones del dispositivo son iguales que las de la pantalla virtual.
El juego aparecerá escalado en función de la pantalla del dispositivo sin ninguna deformación.
Esta solución es muy sencilla de implementar y funciona en todos los casos.

Solución para las aplicaciones

Paradójicamente, el caso de las aplicaciones es algo más complejo que el de los juegos (aunque dije que el desarrollo de juegos es más difícil que el de aplicaciones).
En este caso, la aplicación tiene que mostrar una serie de elementos (widgets) en la pantalla y no siempre lo mejor es que salga centrada en pantalla. Por ejemplo, una aplicación que tenga una barra superior con algunas opciones de menú tiene que salir siempre arriba del todo, no vale que salga un poco más abajo por causa de las bandas del letterbox. Igualmente, si tenemos pestañas abajo, éstas tiene que salir abajo del todo.
Mi solución en este caso, es usar de nuevo "letterbox" como modo de escalado (no quiero deformaciones ni pérdida de información), pero en este caso alineo la pantalla virtual a la parte superior. Mi fichero config.lua sería algo así como:

application = {
    content = {
        width = 320,
        height = 480, 
        scale = "letterBox",
        xAlign = "center",
        yAlign = "top",
    },
}

De esta forma consigo que el contenido se visualice a partir de la parte superior de la pantalla. El problema entonces es cómo conseguir rellenar el espacio sobrante por abajo. Lo que hago es, utilizando las constantes:

display.actualContentWidth
display.actualContentHeight

puedo situar los elementos inferiores ajustados a la parte inferior de la pantalla (en función de estas constantes). Y el espacio que sobra en el centro, lo utilizo para los elementos centrales.
Como se puede intuir, la parte central no va a tener un tamaño fijo, sino que dependerá de las proporciones del dispositivo físico.
Normalmente la parte central suele ser una lista de elementos con scroll o algo similar, con lo cual, es fácilmente adaptable a un tamaño variable.
Ya veremos ejemplos de todo esto en futuras entradas.



miércoles, 24 de agosto de 2016

Lua - Parte 2

Variables, valores y tipos

Lua es un lenguaje tipado dinámicamente. Para los que saben javascript, esto es sencillo de entender. ¿Qué significa que un lenguaje es tipado dinámicamente? Es muy sencillo. En lenguajes como Java, cuando se declara una variable hay que declarar su tipo, int, float, String o lo que sea, y esa variable sólo podrá almacenar valores del tipo declarado (o bien de una clase derivada).
En lenguajes tipados dinámicamente, como Lua, una variable puede contener un valor de cualquier tipo, o dicho más exactamente, puede apuntar a valores de cualquier tipo. Además, es posible que una variable que apunte a un valor de un tipo, más tarde apunte a un valor de otro tipo.
Por ejemplo:

    contador = 14

Estamos declarando una variable que se llama contador y que apunta a un valor de tipo numérico que vale 14. Se observa que no hemos declarado ningún tipo para la variable.
Más adelante podríamos hacer:

    contador = "43"

Ahora, la misma variable contador apunta a otro valor, esta vez de tipo string.

Tipos de datos en Lua:

  • nil - indica que la variable no ha sido inicializada (también se puede asignar nil a una variable explícitamente).
  • boolean - puede ser true o false.
  • number - cualquier número, entero o real. Lua utiliza punto flotante de doble precisión para todos los números.
  • string - cadena de caracteres.
  • function - un bloque de código que se puede invocar.
  • table - es el tipo más complejo que tiene Lua. Más adelante veremos espcíficamente las tablas.
Una variable se puede declarar en cualquier lugar simplemente asignándole un valor:

    contador = 14

Cuando se declara una variable de esta forma, tiene un ámbito global y existirá durante toda la ejecución del programa. Podremos acceder a esta variable desde cualquier punto del programa. Si queremos que el recolector de basura elimine la memoria ocupada por la variable, tenemos que asignarle nil:

    contador = nil

Se dice que el ámbito o scope de esta variable es global. Pero también existe un ámbito de bloque, por ejemplo dentro de una función:

    function calculate()
        local total = 7
    end

Al poner local, la variable total tiene ámbito de bloque: sólo existe dentro de la función, y desaparecerá cuando retorne la función. El recolector de basura eliminará la memoria ocupada por la variable cuando retorne la función (incluso aunque no le asignemos nil).
Se recomienda siempre utilizar local para las variables, excepto cuando deseemos que una variable tenga ámbito global. Cuando dentro del programa se utiliza una variable (sin usar local), Lua busca en el ámbito local para ver si existe, si no existe, busca en el bloque superior y así sucesivamente hasta llegar al ámbito global. Si no existiera, la variable se crea. El rendimiento será muy superior si declaramos todas las variables local, para evitar la cadena de búsquedas de Lua. Además, todos sabemos que las variables globales no son buenas, porque es muy fácil cometer un error y sobreescribirlas en algún lugar del programa sin darnos cuenta.
También hay que tener en cuenta que cuando declaramos una variable local en un bloque, esta variable se utiliza en el bloque aunque exista otra con el mismo nombre en un bloque externo o bien en el ámbito global. Por ejemplo:

    contador = 3
    function incrementar()
        local contador = contador + 1
    end
    -- aquí el valor de contador es 3

Hay una forma de acceder directamente a una variable global, aunque tengamos variables locales con el mismo nombre y además, evitando la cadena de búsqueda de Lua:

    contador = 3
    function incrementar()
        local contador = contador + 1
        _G.contador = _G.contador + 1
    end
    -- aquí el valor de contador es 4

Lua almacena todas las variables globales en una tabla llamada _G, por tanto podemos acceder a cualquier variable global a través de esta table.

Las variables locales de bloque no sólo se pueden utilizar dentro de una función, también se pueden utilizar en otros bloques como if o bucles.

En Lua se pueden realizar asignaciones múltiples:

    local x, y = 3, 4

Esto permite realizar hacer un swap de dos variables de una forma muy sencilla:

    x, y = y, x

Expresiones y operadores

Los operadores y expresiones en Lua son muy similares a los de otros lenguajes de programación.
Operadores matemáticos:
  • + suma
  • - resta o negativo
  • * multiplicación
  • / división
  • % módulo
  • ^ exponenciación
Operadores de comparación (retornan true o false):
  • == igualdad (si los tipos no son iguales, retorna false)
  • ~= desigualdad
  • < menor que
  • > mayor que
  • <= menor o igual que
  • >= mayor o igual que
Operadores lógicos:
  • and
  • or
  • not
Los operadores lógicos consideran que false y nil son false, y todos los demás valores son true.
Los operadores and y or hacen una evaluación con corto-circuito, es decir, si el primer valor de un and es false, no evalúa el segundo, y si el primer valor de un or es true, no evalúa el segundo.

Operador de concatenación:
  • .. concatenación de strings y números
Operador longitud:
  • # longitud de un array (veremos este operador cuando estudiemos las tablas, porque un array es una tabla en Lua)