Bueno,retomando el tema del manejo de escenas,ahora le toca el turno al gestor de escenas
Gestor de escenas
El gestor será el encargado de guardar las escenas de nuestro juego
y también de mantener el ciclo de vida de las mismas. Nuestro
pequeño gestor será capaz de mantener una y sólo una escena en
pantalla, quedando el resto de escenas guardadas dentro del gestor
para un posterior uso.
Retomando nuestro
archivo Escena.lua, creado en un post anterior, podremos ver como el
ejemplo de escena, que os mostré, contenía varias funciones a sobre
escribir y que la mayoría dejamos en desuso. Esto fue así, porque
será ahora cuando el gestor use todas estas funciones para
mantenerlas en pantalla.
Nuestro gestor de
escenas va a contener las siguientes funciones:
- construir_escena(nombre): A esta función no se la llamará directamente, si no que será llamada por el propio gestor, cuando queramos queramos generar una nueva escena.
- nueva_escena(nombre): Función que usaremos para crear una nueva escena. La función recibe una cadena de texto con el nombre de la escena a crear.
- cambiar_escena(nombre): Función que usaremos para navegar entre las escenas del gestor. La función recibe el nombre de la escena y si la encuentra en el gestor, la coloca como la escena activa.
- eliminar_escena(nombre): Función que usaremos para eliminar, completamente, una escena del gestor.
- load(): Será llamada desde love.load y nunca más, durante la ejecución del programa, se volverá a pasar por ella.
- update(dt): Esta función es llamada por love.update(dt). En esta función se controla toda la lógica del gestor y al mismo tiempo se actualiza la escena activa en pantalla.
- draw(): Función llamada desde love.draw y encargada de dibujar la escena activa en pantalla.
Para construir
nuestro gestor, crearemos un nuevo proyecto con nuestro main.lua, el
archivo Escena.lua de la entrada anterior y un nuevo archivo llamado
GestorDeEscenas.lua.
Dentro de nuestro
main.lua generamos la estructura de nuestro programa en Love2d
function love.load()
--Aquí
crearemos las variables y cargaremos los recursos
end
function love.update(dt)
--Aquí
realizaremos la actualización lógica de la aplicación
end
function love.draw()
--Aqui
se realizara todo el proceso de dibujar la pantalla
end
Ahora lo
interesante. Dentro de GestorDeEscena.lua empezamos a escribir lo
siguiente
--[[
Gestor de escenas maneja las diferentes escenas
disponibles en un juego.
El gestor es capaz de mantener varias escenas
en su interior, pero sólo una podrá estar activa y
visible en pantalla.
]]--
GestorDeEscenas=
{
--Llamamos al archivo escena y lo guardamos
dentro del gestor
--La idea es dejar al cargo del gestor la
creación de nuevas escenas
baseEscena=require("escena"),
--Será la tabla que contendrá todas las
escenas pero.
-- en un principio iniciamos la variable a
nil(sin nada)
escenas=nil,
--escena a ocultar fruto de un cambio de
escena en el gestor.
escenaAOcultar=nil,
--Tabla que contendrá todas las escenas a
eliminar del gestor.
escenasAEliminar={},
--Nombre de la escena activa en todo momento.
escenaActiva=nil
}
Desde ahora debemos tener en cuenta, que será el gestor el encargado
de generar las escenas.
Después pasaremos a construir la función construir_escena(nombre)
que se encargará de suministrar, de una nueva escena, a la función
nueva_escena(nombre). Esto
quiere decir, que esta función no será llamada directamente por
nosotros a la hora de usar el gestor.
--[[Función encargada de crear una nueva
escena y almacenarla en el gestor.
Esta función no se llama directamente.Esta
función sera llamada, automáticamente,
cada vez que usemos la función
nueva_escena.]]--
function
GestorDeEscenas:construir_escena(nombre)
--Usa el objeto escena para proveer una nueva
escena,
--que será automaticamente guardada dentro
del gestor antes de retornarla
--a la función nueva_escena
self.escenas[nombre]=self.baseEscena:new()
self.escenas[nombre].nombre=nombre
self.escenaActiva=nombre
return
self.escenas[self.escenaActiva]
end
La siguiente función, será la que usaremos
para crear infinitas escenas dentro del gestor.
--[[Genera una nueva escena, la almacena, la
deja como la escena activa y al final la retorna]]--
function
GestorDeEscenas:nueva_escena(nombre)
--Pregunta si la variable escenas aun vale nil
y si es así,
--genera por primera vez la tabla dentro de
ella. Acto seguido genera la nueva escena
--y la retorna.
if (self.escenas==nil)then
self.escenas={}
return
self.construir_escena(self,nombre)
--Si la tabla escena ya está creada, pregunta
si el nombre de la escena a crear ya existe en el gestor.
--Después pregunta si ya tiene una escena
activa y si es así la prepara dentro de escenaAOcultar
--para volver a almacenarla desde update. Acto
seguido genera la nueva escena y la retorna.
elseif
(self.escenas[nombre]==nil) then
if (self.escenaActiva~=nil)
then
self.escenaAOcultar=self.escenaActiva
end
return
self:construir_escena(nombre)
end
--En caso de no poder construir la escena la
función retornará el valor nil
return nil
end
Para cambiar entre las escenas contenidas en el
gestor usaremos la siguiente función
--[[Esta función recibe el nombre de una
escena y si
se encuentra dentro del gestor, la coloca como
la escena activa]]--
function
GestorDeEscenas:cambiar_escena(nombre)
--Preguntamos si existe
la escena en el gestor
if
(self.escenas[nombre]~=nil) then
--Preguntamos si la
escena a mostrar no se esté mostrando ya
if
(self.escenaActiva~=nombre) then
--Preguntamos si
existe ya alguna escena activa
--y si es así , la pasamos a escenaAOcultar
para
--ocultarla desde el método update(dt)
if
(self.escenaActiva~=nil) then
self.escenaAOcultar=self.escenaActiva
self.escenas[self.escenaActiva].activa=false
end
end
--Si todo lo anterior
fue correcto, pasamos el nombre
--a la variable escenaActiva y a partir de
aquí el método
--update(dt) se encargará del resto
self.escenaActiva=nombre
end
end
La próxima función será la encargada de
marcar las escenas a eliminar del gestor. Digo marcar porque,
realmente, la acción de eliminar una escena del gestor será
realmente en el método update(dt). La función sería la siguientes
--[[Función que se encarga de agrupar en una
tabla, todas las escenas a eliminar del gestor,
después la función update(dt) será la
encargada de eliminar las escenas aquí agrupadas]]--
function
GestorDeEscenas:elimiar_escena(nombre)
indice=1
--Nos aseguramos de que
la escena a eliminar esté en el gestor
if
(self.escenas[nombre]~=nil) then
--Si la escena a eliminar es la escena
activa, primero nos aseguramos
--de que ya no se vuelva a mostrar en
pantalla
if
(self.escenaActiva==nombre) then
self.escenaAOcultar=self.escenas[nombre]
self.escenaActiva=nil
end
--Insertamos la escena a eliminar dentro de
la
--tabla para su posterior borrdo.
if
(#self.escenasAEliminar>0) then
indice=#self.escenasAEliminar
end
self.escenasAEliminar[indice]=self.escenas[nombre]
end
end
La función load será llamada una sola vez
desde el método principal love.load. Por ahora esta función asegura
que la primera vez que se pase por la función update(dt) la escena
inicial ya este viva. Perfectamente podríamos a ver prescindido por
ahora de esta función, pero por mantener una buena construcción
casi prefiero ponerla.
--[[Función que será llamada desde el
main.lua.
La función carga los datos de la escena
actualmente
apuntada, en el gestor, por escenaActiva]]--
function
GestorDeEscenas:load()
if
(self.escenaActiva~=nil) then
self.escenas[self.escenaActiva].load()
end
end
La función draw, será la encargada de dibujar
la escena activa en pantalla. Para esta tarea la función draw tendrá
en cuenta que la escena ya este viva y en pantalla.
--[[Función llamada desde el main.lua y que se
encarga
de dibujar la escena activa en el gestor]]--
function
GestorDeEscenas:draw()
if
(self.escenaActiva~=nil) then
--[[Aquí se dibuja el
contenido de la escena activa, teniendo en cuenta que ya esté viva y mostrandose en pantalla]]--
if
(self.escenas[self.escenaActiva].estaViva==true) and (self.escenas[self.escenaActiva].estaEnPantalla==true) then
self.escenas[self.escenaActiva].draw()
end
end
end
Y por fin el salsa del asunto, la función
update(dt). Esta función sera la encargada real de llevar toda la
lógica del gestor y en su proceso se realizarán las tareas de
eliminar, mostrar, cargar y actualizar las escenas del mismo durante
la ejecución de un juego.
--[[Función llamada desde el main.lua y que se
encarga
de actualizar toda la lógica del gestor y las
escenas contenidas en el mismo]]--
function
GestorDeEscenas:update(dt)
--iteramos sobre la
tabla "escenasAEliminar" para liberar del gestor las
escenas no necesarias
for c=1,
#self.escenasAEliminar do
self.escenasAEliminar[c].hidden()
self.escenasAEliminar[c].destroy()
self.escenasAEliminar[c].estaViva=false
nombre=self.escenasAEliminar[c].nombre
self.escenas[nombre]=nil
self.escenasAEliminar[c]=nil
end
--[[Controlamos el flujo
de actualización de la escena activa en el gestor]]--
if
(self.escenaActiva~=nil) then
--[[Antes de actualizar
preguntamos si la escena ya esta viva,
de no ser así, primero procedemos a pasar
por su función load
y marcamos si variable está viva.
Update no actualiza la escena en esta
vuelta]]--
if
(self.escenas[self.escenaActiva].estaViva~=true)
then
self.escenas[self.escenaActiva].load()
self.escenas[self.escenaActiva].estaViva=true
--[[Preguntamos si la
escena está en pantalla, de no ser así,
procedemos a pasar por su función show.
Update no actualiza la escena en esta
vuelta]]--
elseif
(self.escenas[self.escenaActiva].estaEnPantalla~=true)
then
self.escenas[self.escenaActiva].show()
self.escenas[self.escenaActiva].estaEnPantalla=true
else
--[[Si la escena ya
esta viva y en pantalla, pasamos a actualizarla mediante su función
update(dt)]]--
self.escenas[self.escenaActiva].update(dt)
end
--[[Si el gestor tiene
alguna escena pendiente de ocultar, la hará pasar
aquí por su función hidden]]--
if
(self.escenaAOcultar~=nil) then
if
(self.escenas[self.escenaAOcultar]~=nil)
then
self.escenas[self.escenaAOcultar].hidden()
self.escenas[self.escenaAOcultar].estaEnPantalla=false
end
self.escenaAOcultar=nil
end
end
end
return GestorDeEscenas
Y como marca la última linea, sólo nos
quedaba retornar el gestor que acabamos de construir.
Por no hacer esto más largo, me montaré un
pequeño ejemplo en otro post, mientras tanto hasta la próxima.
No hay comentarios:
Publicar un comentario