Anatomía de un widget button

Uno de los elementos más básicos para construir un juego es el uso de botones. En Corona SDK los botones forman parte de una librería de nombre widget que te da acceso a diversos elementos que puedes usar para construir la interfaz gráfica de usuario (GUI por sus siglas en inglés) como scrollviews, tablas, sliders, tabbars, entre otros.

En esencia un botón es un contenedor que puede llevar una imagen de fondo y puede llevar texto, pero cada uno de estos elementos nos da acceso a una serie de propiedades que nos permitirá manipular el botón y lograr la configuración que mas se adecue a nuestras necesidades. En el código siguiente muestro la creación básica de un botón con imágenes y texto que nos servirá como guía.

  local LIB_WIDGET = require ("widget")

  local buttonOptionsTable = {
      defaultFile = "sprites/btn_green01_normal.png"
      overFile = "sprites/btn_green01_over.png",
      label = "Start",
      fontSize = 40,
      x = 600,
      y = 400
  }

  local greenButton = LIB_WIDGET.newButton(buttonOptionsTable);

El código anterior nos permite generar un botón verde con el texto Start. Si tuvieramos que descomponer las propiedades del botón en partes podríamos identificar 3: texto, imagen e interacción. Veamos cuales son las propiedades a las que tenemos acceso de acuerdo a cada una de estas partes.

Propiedades del texto

  • label : Es el texto que aparecerá dentro del  botón
  • labelAlign : La alineación del texto dentro del área del botón y los valores que puedes usar son left, right y center. Por defecto su valor es center.
  • labelColor : El color del texto dentro del botón, es necesario especificar, por medio de una tabla, los colores para el estado default (o sin presionar) como para el estado over (cuando presionas el botón)
  • labelXOffset , labelYOffset : Modifica la posición por defecto que toma el texto dentro del botón.
  • font : Especifica la fuente a utilizar en el texto desplegado en el botón. Su valor por defecto es native.systemFont
  • fontSize : Es el tamaño de la fuente. Su valor por defecto es 14.

Propiedades de la imagen

  • width, height : El ancho y el alto de la imagen utilizada. Estos números (generalmente del tipo flotante por ejemplo 80.0) son los que determinan el área que ocupará el contenedor del botón.
  • defaultFile : El nombre del archivo de imagen que será utilizada para el estado default (cuando el botón no esta presionado).
  • overFile : El nombre del archivo de imagen que será utilizada para el estado over (cuando el botón esta siendo presionado).

propiedades de interacción

  • id : Permite agregar un identificador para el botón. Es muy útil cuando necesitas crear una sola función que administre las acciones de múltiples botones identicos y que necesitas diferenciar por medio de un String.
  • x, y :  Las coordenadas en donde se posicionará el botón en pantalla.
  • left, top : Posiciona el botón tomando como referencia la esquina superior izquierda como punto de ancla. Si se especifican estos valores anularán las propiedades x , y.
  • isEnabled : Si se define como false, el botón no responderá a eventos touch. Para habilitarlo o deshabilitarlo luego de ser creado se usa la función button:setEnabled().
  • onPress : Una función opcional que será llamada cuando el botón es presionado. La función invocada no requiere que se evalue event.phase ya que por defecto detecta el evento "began".
  • onRelease : Una función opcional que será llamda cuando el botón deja de ser presionado (siempre y cuando el touch se encuentre sobre el botón). La función invocada no requiere que se evalue event.phase ya que por defecto evalúa el evento "ended".
  • onEvent : Una función opcional que solo se debe especificar si onPress y/o onRelease no han sido configurados. La función invocada te permite evaluar event.phase con los valores "began", "moved" y "ended".

Ejemplos de configuraciones.

En la imagen de la figura 1 podemos observar como el texto “Start” dentro del botón aparece ligeramente pegado a la parte superior del botón cuando lo que se espera es que dicho texto aparezca centrado, de vital importancia si eres el tipo de persona que le presta atención a los pequeños detalles. Hay ocasiones que las fuentes tipográficas que estamos usando dentro de nuestro juego tienen algún ajuste mismo que produce este tipo de problemas, afortunadamente usando la propiedad labelYOffset es posible corregirlo sin mayor complicación.

Figura 1- correción de alineación vertical de texto de un botón.

A continuación podemos ver el codigo original y como fue corregido:

  -- Código original, botón sin corrección
  local buttonOptionsTable = {
      defaultFile = "sprites/btn_green01_normal.png",
      overFile = "sprites/btn_green01_over.png",
      label = "Start",
      font = "AppleBerry.ttf",      -- Esta fuente produce el problema de alineación
      fontSize = 40,
      x = 360,
      y = 270
  }

  local greenButton = LIB_WIDGET.newButton(buttonOptionsTable);



  -- Código modificado, imagen con corrección
  local buttonOptionsTable = {
      defaultFile = "sprites/btn_green01_normal.png",
      overFile = "sprites/btn_green01_over.png",
      label = "Start",
      font = "AppleBerry.ttf",
      fontSize = 40,
      x = 360,
      y = 270,
      labelYOffset = 5          -- Se ajusta la posición Y del texto
  }

  local greenButton = LIB_WIDGET.newButton(buttonOptionsTable);

Como se puede observar en el ejemplo no es necesario poner las propiedades en un orden en especifico para que sean aplicadas.

Otro caso común es cuando creamos un menú de botones para navegar entre diferentes pantallas. Si bien se puede crear una función para cada elemento del menú asi como crear una tabla de propiedades para cada botón es mucho mas simple crear una sola función que administre las acciones y diferenciarlos por el ID del botón y una sola tabla que defina las características de los botones. Para ello una vez creados accederemos a sus propiedes para asignar los valores que los harán diferentes. Veamos el ejemplo:

  function fnt_elBotonPresionado(event)
      local botonPresionado = event.target  -- Obtiene 

      if botonPresionado.id == "MENU_PLAY" then
          -- Ir a la pantalla de juego
      elseif botonPresionado.id == "MENU_TUTORIAL" then
          -- Ir a la pantalla tutorial
      elseif botonPresionado.id == "MENU_FRIENDS" then
          -- Ir a la pantalla de amigos
      elseif botonPresionado.id == "MENU_MESSAGES" then
          -- Ir a la pantalla de mensajes
      end

  end

  -- Configuración base que compartirán todos los botones
  local buttonOptionsTable = {
      defaultFile = "sprites/btn_green01_normal.png",
      overFile = "sprites/btn_green01_over.png",
      fontSize = 35,
      onRelease = fnt_elBotonPresionado
  }

  local boton1 = LIB_WIDGET.newButton(buttonOptionsTable)
  boton1.x = 200
  boton1.y = 200
  boton1:setLabel("Jugar")
  boton1.id = "MENU_PLAY"

  local boton2 = LIB_WIDGET.newButton(buttonOptionsTable)
  boton2.x = 500
  boton2.y = 200
  boton2:setLabel("Instrucciones")
  boton2.id = "MENU_TUTORIAL"

  local boton3 = LIB_WIDGET.newButton(buttonOptionsTable)
  boton3.x = 200
  boton3.y = 300
  boton3:setLabel("Amigos")
  boton3.id = "MENU_FRIENDS"

  local boton4 = LIB_WIDGET.newButton(buttonOptionsTable)
  boton4.x = 500
  boton4.y = 300
  boton4:setLabel("Mensajes")
  boton4.id = "MENU_MESSAGES"

Veamos que es lo que esta pasando en el código anterior:

  • En primer lugar es importante mencionar que en LUA y corona SDK no es posible que usemos un nombre de función o variable si no ha sido previamente declarada / inicializada. Es por ello que la función que se invoca cuando presionamos el botón aparece antes de que configuremos los botones.
  • La función de nombre fnt_elBotonPresionado lleva un parámetro de nombre event, al ser un evento del botón dicho parámetro se transmite de forma automática, es decir, cuando lo configuremos como evento en nuestro botón no es necesario que agreguemos los parentesís y algún valor en particular para que esta función reciba dicho parámetro.
  • Dentro de la misma función fnt_elBotonPresionado podemos ver que hay una instrucción que dice event.target y que guarda algo en una variable de nombre botonPresionado. Cuando una misma función esta siendo utilizada / invocada por varios botones event.target nos ayuda a obtener el botón que especificamente fue el que ejecutó la función.
  • Como la variable botonPresionado tiene guardada la referencia de que botón fue el que el usuario presionó, podemos acceder a todas sus propiedades como lo es el ID o el texto (label). Es por ello que podemos definir diversas acciones a seguir dependiendo el ID del botón que hemos presionado.
  • La tabla de propiedades que definene las características de nuestros botones de nombre buttonOptionsTable solo tiene los elementos que comparten todos los botones, que en este caso son las images, el tamaño de la fuente y la función que será invocada cuando el botón deje de estar presionado. Como se puede observar, solo se coloca el nombre de la función sin poner algún parámetro pues, como mencione un par de puntos atrás, el parámetro event se transmite de forma automática.
  • Después de la tabla que configura la base de nuestros botones se crea cada uno de ellos guardándolos en una variable para poder manipular sus propiedades. Las diferencias entre cada uno de ellos son: La posición del botón, el texto que muestran y el ID de cada uno de ellos, propiedades que modificamos en cada botón una vez que han sido creados.

El resultado de esa codificación nos permite obtener una pantalla como la siguiente:

Figura 2 – Construcción de un menú de botones.

Como se puede observar en la figura 2 no hace falta que desde el inicio todas las propiedades estén definidas en la creación del botón ya que se pueden manipular después de haber sido creado.

Entender y conocer las propiedades a las que tenemos acceso nos da la libertad para configurar a nuestro gusto una interfaz. ¿Hay otros casos o ejemplos de uso de botones a los que te hayas enfrentado? Puedes dejarnos un comentario y con gusto integraremos mas ejemplos especificos de uso y configuraciones de botones.

Espero hayas disfrutado y aprendido muchas cosas de esta entrada y por favor siéntete libre de compartir esta información en tus redes sociales para que otras personas interesadas también puedan conocer algo nuevo y que les pueda ayudar en sus proyectos futuros. ¡Hasta la próxima!