Un saludo a todos, hoy les quiero explicar como crear una simple interfaz gráfica con Love2D que nos pueda ayudar a desarrollar más adelante nuestro propio código adaptado al programa que queramos desarrollar. Aquí explicaré como crear un botón, una caja de texto, deslizador y una caja de selección.
Trataré de hacer el código lo más pequeño posible para que se pueda entender todo lo que hace y como lo hace y espero les sirva de ayuda en sus proyectos.
Las funciones que tendremos serán las siguientes:
function puntoEnRectangulo(puntoX,puntoY,rectX,rectY,rectAncho,RectAlto)
function nuevoControl(texto,x,y,ancho,alto,tipo)
function dibujaControles()
function controlTextInput(k)
function controlKeyPressed(tecla)
function controlMouseReleased(x,y,boton)
function controlWheelMoved(w)
function ajustaFoco(control) --el control que se pase será el activo
function obtenerControles() --devuelve la tabla "listaControles"
function agregarControl(control) --agrega un control a "listaControles"
function removerControl(control) --remueve un control de la lista
function ajustarValorDeslizador(control,valor)
local function calculaValorDeslizador(control,cursorx)
local function calculaPorcentajeDeslizador(distancia,valorMaximo)
local function ajustaTexto(control)
Las variable internas son las siguientes:
local enFoco = nil
local listaControles = {}
temaControles = {
colorFondo = {0.85,0.85,0.85},
colorTexto = {0,0,0},
fondoTexto = {1,1,1},
colorFoco = {0,0.5,1},
colorDeslizador = {0.1,0.2,1},
colorMarca = {0.1,0.2,1},
colorBorde = {0.6,0.6,0.6}
}
Ahora veamos como funcionará todo esto. Con la función "nuevoControl" crearemos cualquiera de los controles antes nombrados indicando en el parámetro "tipo" la clase de control al que pertenecerá, al control que obtenemos le podemos modificar sus valores y luego lo agregamos a la lista de controles, cuando con el puntero del ratón hagamos clic sobre algún control, este pasa a estar en el foco y por lo tanto recibirá entrada de texto si es de tipo "texto" o si se usa la rueda del ratón si es de tipo "deslizador" y si es de tipo "boton" ejecutará la acción que se le configuró. La función "dibujaControles" sabrá como dibujar el componente de acuerdo a su tipo, y debido a que todos comparten la mayoría de las características no se necesita código muy complejo para realizar esta tarea.
Veamos la función "nuevoControl", aquí creamos una tabla llamada "control" y le agregamos todo este conjunto de variables, los nombres son bastante claros para identificar su uso, luego devolvemos la variable control para ser usada y modificada a nuestra necesidad. La variable "acción" será una función que deseemos y que será invocada al hacer clic sobre el control.
function nuevoControl(texto,x,y,ancho,alto,tipo)
local control = {}
control.x = x
control.y = y
control.ancho = ancho
control.alto = alto
control.tipo = tipo
control.texto = texto
control.accion = nil
control.valorDeslizador = 0
control.valorMaximoDeslizador = 100
control.incrementoDeslizador = 1
control.porcentajeDeslizador = 0
control.marcado = false
control.margenTexto = 0
control.margen = {0,0,0,0} --arriba,derecha,abajo,izquierda
control.sinBorde = false --no dibuja el borde del rectángulo
control.sinFondo = false --no dibuje el fondo
control.sinFoco = false --si está enfocado no dibuja el foco
if tipo == "deslizador" then
control.texto = "0"
end
return control
end
La función "dibujaControl" es bastante simple, en un bucle que atraviesa la tabla "listaControles" y va dibujando los rectángulos con los colores del tema, y muestra el texto que el componente tenga. De acuerdo al tipo de componente se agregan elementos extra como por ejemplo cuando es tipo "marca" se agrega un cuadrado al lado del texto para identificar si el control está marcado o no. El texto es recortado si es demasiado largo y el valor de "margen" ayuda a mover el texto dentro de su área limitando también su visibilidad.
function dibujaControles()
for indice,control in ipairs(listaControles) do
if control.tipo == "texto" then
love.graphics.setColor(unpack(temaControles.fondoTexto))
else
love.graphics.setColor(unpack(temaControles.colorFondo))
end
if not control.sinFondo then
love.graphics.rectangle("fill",control.x,control.y,control.ancho,control.alto)
end
if control.tipo == "deslizador" then
love.graphics.setColor(unpack(temaControles.colorDeslizador))
love.graphics.rectangle("fill",control.x,control.y,control.ancho*control.porcentajeDeslizador,control.alto)
end
love.graphics.setColor(unpack(temaControles.colorTexto))
local cheqMargen = 0
local altoLetra = 0
if control.tipo == "marca" then
altoLetra = love.graphics.getFont():getHeight()
cheqMargen = altoLetra + 5
end
local clipx = control.x + control.margen[4]
local clipy = control.y + control.margen[1]
local clipAncho = control.ancho - control.margen[4] - control.margen[2] - cheqMargen
local clipAlto = control.alto - control.margen[1] - control.margen[3]
love.graphics.setScissor(clipx,clipy,clipAncho,clipAlto)
love.graphics.print(control.texto,control.x + control.margen[4] - control.margenTexto,control.y + control.margen[1])
love.graphics.setScissor()
love.graphics.setColor(unpack(temaControles.colorMarca))
if control.marcado then
love.graphics.rectangle("fill",control.x + control.ancho - cheqMargen,control.y + control.margen[1],altoLetra,altoLetra)
else
love.graphics.rectangle("line",control.x + control.ancho - cheqMargen,control.y + control.margen[1],altoLetra,altoLetra)
end
if enFoco == control and not control.sinFoco then
love.graphics.setColor(unpack(temaControles.colorFoco))
love.graphics.rectangle("line",control.x,control.y,control.ancho,control.alto)
elseif not control.sinBorde then
love.graphics.setColor(unpack(temaControles.colorBorde))
love.graphics.rectangle("line",control.x,control.y,control.ancho,control.alto)
end
end
end
Para ayudar en los momentos que se escriba dentro de una caja de texto tenemos la función "ajustaTexto" que calcula si el texto supera al área del control y si es así aumentando al valor del "margenTexto" para ver siempre el final del texto mientras se escribe, si el control ya no tiene el foco el "margenTexto" regresa a ser cero. El valor "margenTexto" es usado durante el dibujado para mover el texto a la izquierda.
local function ajustaTexto(control)
local anchoTexto = love.graphics.getFont():getWidth(control.texto)
local anchoRecorte = control.ancho - control.margen[2] - control.margen[4]
local diferencia = anchoRecorte - anchoTexto
if diferencia < 0 then
control.margenTexto = math.abs(diferencia)
else
control.margenTexto = 0
end
end
Es necesario que cuando se haga clic sobre un control de tipo "deslizador" se modifique el tamaño del rectángulo indicador de acuerdo a la posición dónde se coloque el cursor del ratón. Las siguientes funciones trabajan en conjunto para esto, "calculaPorcentajeDeslizador" devuelve el valor que es utilizado para calcular el ancho del rectángulo durante el dibujado, "calculaValorDeslizador" se utiliza cuando hacemos clic en algún punto del área del control, y "ajustaValorDeslizador" cuando queramos modificar el valor por medio de código y así pueda ser mostrado el cambio durante el dibujado.
local function calculaPorcentajeDeslizador(distancia,valorMaximo)
local porcentaje = math.modf((100 * distancia)/valorMaximo)
return porcentaje/100
end
local function calcularValorDeslizador(control,cursorx)
local distancia = cursorx - control.x
control.porcentajeDeslizador = calculaPorcentajeDeslizador(distancia,control.ancho)
control.valorDeslizador = control.valorMaximoDeslizador * control.porcentajeDeslizador
control.texto = ""..control.valorDeslizador
end
function ajustaValorDeslizador(control,valor)
if valor < 0 then
valor = 0
elseif valor > control.valorMaximoDeslizador then
valor = control.valorMaximoDeslizador
end
control.valorDeslizador = valor
control.texto = ""..control.valorDeslizador
control.porcentajeDeslizador = calculaPorcentajeDeslizador(control.valorDeslizador,control.valorMaximoDeslizador)
end
Las funciones "controlTextInput", "controlKeyPressed", "controlMouseReleased", "controlWheelMoved" deben colocarse en los lugares respectivos dentro de las funciones de Love2D para que los controles puedan reaccionar correctamente al teclado y el ratón. Estas funciones son bucles que verifican cada control dentro de la lista, si el control está en foco y de acuerdo al tipo se actualiza su valor correspondiente.
Veamos un ejemplo simple:
require "controles"
function love.load()
love.keyboard.setkeyRepeat(true)
love.graphics.setBackgroundColor(0.9,0.9,0.9)
etiqueta = nuevoControl("Etiqueta",5,5,100,25,"etiqueta")
etiqueta.margen = {5,5,5,5}
deslizador = nuevoControl("",5,35,100,25,"deslizador")
deslizador.margen = {5,5,5,5}
boton = nuevoControl("Botón",5,65,100,25,"boton")
boton.margen = {5,5,5,5}
boton.accion = function () --escribe tu código aquí end
texto = nuevoControl("",5,95,100,25,"texto")
texto.margen = {5,5,5,5}
marca = nuevoControl("Marca",5,125,100,25,"marca")
marca.margen = {5,5,5,5}
agregarControl(etiqueta)
agregarControl(deslizador)
agregarControl(boton)
agregarControl(texto)
agregarControl(marca)
end
function love.textInput(k)
controlTextInput(k)
end
function love.keypresed(key)
controlKeyPressed(key)
end
function love.wheelmoved(x,y)
controlWheelMoved(y)
end
function love.mousereleased(x,y,boton)
controlMouseReleased(x,y,boton)
end
function love.draw()
dibujaControles()
end
Y así se vería este ejemplo.
Y este un video corto.
También creé una pequeña calculadora como práctica y aquí te dejo un video corto.
Como puedes ver es una interfaz muy simple que espero te sea útil y además estoy seguro de que podrás crear algo mucho mejor. Te dejaré el código aquí para que puedas probarlo.
No se puede descargar el código. Gracias.
ResponderEliminarEl enlace funciona, ya fué verificado. espero puedas acceder y descargarlo
Eliminar