https://www.segasaturno.com/portal/viewtopic.php?f=33&t=7676&p=79073#p79073
-----------------------------------
Ryo Suzuki
10 Junio 2014, 07:03 PM

Re: Trasteando con el Lua Player de Saturn (Tutorial)
-----------------------------------
Después del arrollador éxito (es lo que esperaba, jeje) sigo con este tema.

Antes de nada os comentaré dos cosas. La primera es este framework para hacer juegos 2D con Lua que acabo de descubrir:

https://www.love2d.org/

En principio no nos sirve para nada con el Lua de la Saturn, pero ahí lo dejo para investigarlo porque puede ser interesante.

También, como documentación y os lo pongo ahora todo junto que luego me lío con el rollo y se me olvida, es muy bueno esto:

http://www.rockin-b.de/saturn/saturngametutorial/SaturnGameTutorial.htm

Podríamos decir que es la biblia de la programación en Sega Saturn de la mano del maestro The Rockin'-B'. Aunque es para Orbit, muchos conceptos son aplicables a lo que podamos hacer con Lua. Esto lo deberíamos guardar a buen recaudo para consultar en cualquier momento.

Y bueno, voy a la lección de hoy que se me hace tarde...


[b]¿Donde están las subrutinas?[/b]

A medida que iba haciendo mis pruebas y chapucillas para intentar aprender algo de programación en Saturn con este Lua Player una duda se iba planteando en mi cabeza. Hasta ahora hemos hecho cosas como imprimir texto en pantalla, manejar movidas con condicionales y actuar en consecuencia, trato con variables, detectar qué pasaba con el mando, etc... El que caso es que siempre pensé qué sucedería cuando el código se fuese complicando un poco más y a su vez fuese creciendo.

Es decir, recordando los buenos tiempos de BASIC para los veteranos del lugar, ¿dónde están las rutinas y subrutinas? Trozos de código a los que llamabas con GOTO O GOSUB y luego retornabas con RETURN. O sea, partes de código que se encarguen de una cosa en concreto y que podamos llamar desde el programa principal a nuestro gusto.

Para que me entendáis con un ejemplo práctico, imaginaos que tenemos una porción de código -como hemos visto en los ejemplos que he ido creando- que se encargue de comprobar si una variables es mayor que tal número, u otro que chequeé si hay un mando conectado en el puerto 2, o quizás una parte de código que genere dos valores al azar y se los asigne a una variable...

El meollo es, vamos a suponer que esto lo necesitamos hacer varias veces en nuestro programa. Cada vez que necesitemos realizar estas operaciones tendremos que volver a escribir/colocar ese código con los comandos correspondientes... ¿No sería mejor llamar a esa rutina cuando nos haga falta y que lo haga las veces que sea necesario y cuando nos convenga manejándolo nosotros?

En BASIC, y creo que en otros lenguajes antiguos, a esto se llamaba rutinas. En Lua, se llaman funciones (queda más cool) y vamos a explicarlo con un pequeño y sencillo ejemplo que he creado:

[code linenumbers=false]slInitSystem(TV_320x240,NULL,1) 


function PRUEBA()
slPrint("Esto es la funcion PRUEBA", 1, 1)
end

function MIERDA()
slPrint("Esto es la funcion MIERDA", 2, 3)
end

function NOSEUSA()
slPrint("Esto es la funcion NOSEUSA", 3, 5)
end

PRUEBA()
MIERDA()

while true do slSynch() end[/code]

Ejecutamos en el emu como ya sabemos y obtenemos algo tan espectacular como esto: :mrgreen: 

 [img]http://www.segasaturno.com/portal/files/images/2/funciones_lua_saturn.jpg[/img]

Puede parecer una tontería pero nos resuelve el problema que teníamos antes y nos dará mucha vida en el futuro. Podemos invocar a rutinas que tengamos hechas cuando queramos y acceder a ellas cuantas veces las necesitemos.

Además podemos dividir nuestro código en diferentes parte más definidas y a la hora de abordar lo que queramos hacer será mucho mejor y más organizado.

Lo que hemos realizado en este ejemplo que he puesto es definir tres sencillas funciones con su código específico y luego hemos llamado solo a dos de ellas.

Lo comento aunque salte a la vista:

[code linenumbers=false]slInitSystem(TV_320x240,NULL,1) -- Inicia el sistema SGL


function PRUEBA() -- Definimos la función llamada PRUEBA
slPrint("Esto es la funcion PRUEBA", 1, 1) -- Esto para no liaros es el código simple de esta función, podría ser mucho más complicado, ya veréis más adelante...
end  -- Finalizamos lo que contiene esa función

function MIERDA()  -- Ahora defino otra función que se llama MIERDA
slPrint("Esto es la funcion MIERDA", 2, 3) -- Lo mismo, la función tiene un print sencillo
end -- Hasta aquí llega esta función

function NOSEUSA() -- Definimos una función que no vamos a usar en este programa, es para que se vea que la podemos llamar si queremos o no...
slPrint("Esto es la funcion NOSEUSA", 3, 5) -- Una cosa que no se va a llegar a ver que es lo que tiene esta función de código
end -- Se acabó esta función, amigos

PRUEBA() -- Invocamos a esta función, así se hace. Esto es lo primero que ejecuta este programa, el código que haya en esa función
MIERDA() -- después invocamos a esta segunda función llama MIERDA y que hemos definido antes

while true do slSynch() end-- Lo mete en el bucle infinito que tanto nos gusta

[/code] 

Lua puede llamar (y manejar) funciones escritas en su propio lenguaje. Pero no solo eso, además puede ejecutar funciones escritas en C!! Esto es algo que todavía no sé bien cómo va, pero que he visto en los ejemplos que vienen con el Lua Player que en ocasiones hacen uso de funciones en C... De hecho, creo que llaman a cosas hechas con el Saturn Orbit.

Pero no nos desviemos del tema. Esta es la forma más simple de definir funciones e invocarlas, pero luego me temo que se pueden hacer llamadas con argumentos y demás, que ya tocaré más adelante cuando lo domine más...


[b]Un ejemplo un poco más elaborado[/b]

Por si acaso no habéis pillado bien para que podemos usar las funciones o pensáis que esto es una soberana chorrada, lo voy a mostrar con un ejemplo que por lo común que es y al que estamos todos muy habituados lo vais a coger sin duda el concepto y para qué nos va a servir.

He perpetrado/improvisado este código:

[code linenumbers=false]
function OPCIONES()
slTVOff()
slInitSystem(TV_320x240,NULL,1)
slTVOn()
slPrint("Esto serian las OPCIONES", 2, 2)
while true do slSynch() end
end


function CREDITOS()
slTVOff()
slInitSystem(TV_320x240,NULL,1)
slTVOn()
slPrint("Esto serian los CREDITOS", 2, 2)
while true do slSynch() end
end


function JUGAR()
slTVOff()
slInitSystem(TV_320x240,NULL,1)
slTVOn()
slPrint("Esto seria el JUEGO en si", 2, 2)
while true do slSynch() end
end



local bucle = 1

slInitSystem(TV_320x240,NULL,1)

slPrint("----JUEGO TRAPERO----", 6, 5) 
slPrint("Imaginaos unos graficos que te cagas xD", 1, 10) 


while bucle < 2 do

slPrint("Pulsa A para OPCIONES", 1, 19)
slPrint("Pulsa X para CREDITOS", 1, 21)
slPrint("Pulsa START para JUGAR", 1, 23)

id,ext,data = Smpc_Peripheral(0)
if bit.band(data, PER_DGT_TA) == 0 then OPCIONES()
end
if bit.band(data, PER_DGT_TX) == 0 then CREDITOS()  
end

if bit.band(data, PER_DGT_ST) == 0 then JUGAR()
end


end 



while true do slSynch() end[/code]

Al ejecutarlo nos aparecerá esto:

 [img]http://www.segasaturno.com/portal/files/images/2/juego_saturn_lua.jpg[/img]

Tendréis que echarle algo de imaginación. Imaginaos un juego simple que tiene un menú con tres opciones como veis, lo típico que hemos visto tantas y tantas veces.

Supongamos que pulsamos la X para ver los créditos del juego y ver a sus programadores:

 [img]http://www.segasaturno.com/portal/files/images/2/creditos_lua.jpg[/img] 

Lo mismo pasa con las demás opciones, el programa nos lleva a cada una de ellas. Lo hemos hecho a través de las funciones. En juego en sí sería un código muy complicado que estaría dentro de la función JUEGO y al que llamaríamos cuando el jugador pulse START.

Comento el código por si las moscas:

[code linenumbers=false]
function OPCIONES() -- defino lo que serán las opciones con esta función
slTVOff() -- esto es para limpirar la pantalla luego lo comento mejor
slInitSystem(TV_320x240,NULL,1) -- vuelvo a poner el SGL
slTVOn() -- y enciendo, esto son nuevas librerías de SEGA que ahora explicaré
slPrint("Esto serian las OPCIONES", 2, 2) -- Aqui estaría todo el código de las opciones pertinente
while true do slSynch() end -- Lo meto en un bucle para que no salga de aquí, pero podríamos e incluso deberíamos poder regresar al menú principal, para no complicarlo más lo dejo así.
end -- se acaba aquí la función OPCIONES


function CREDITOS() -- Definimos la función CREDITOS, todo lo demás es igual
slTVOff()
slInitSystem(TV_320x240,NULL,1)
slTVOn()
slPrint("Esto serian los CREDITOS", 2, 2)
while true do slSynch() end
end


function JUGAR() -- Ahora el juego en sí, que seria la función JUGAR
slTVOff()
slInitSystem(TV_320x240,NULL,1)
slTVOn()
slPrint("Esto seria el JUEGO en si", 2, 2) -- Aquí estaría todo el código y el meollo del juego
while true do slSynch() end
end



local bucle = 1 -- Lo voy a meter en un bucle con esta variable para detectar la pulsación del mando

slInitSystem(TV_320x240,NULL,1) -- Esto es lo primero que se va a ejecutar ya que hemos definido las funciones pero aun no hemos llamado a ninguna de ellas

slPrint("----JUEGO TRAPERO----", 6, 5) -- Esto seria el Main Menu del juego típico
slPrint("Imaginaos unos graficos que te cagas xD", 1, 10) 


while bucle < 2 do -- Le pongo una condición que será infinita porque nunca cambiaría y siempre será así, si sabéis alguna manera mejor de hacerlo... soy todo oídos!

slPrint("Pulsa A para OPCIONES", 1, 19)
slPrint("Pulsa X para CREDITOS", 1, 21)
slPrint("Pulsa START para JUGAR", 1, 23)

id,ext,data = Smpc_Peripheral(0) -- Detectamos lo que pulse el jugador como aprendimos en los otros ejemplos que puse
if bit.band(data, PER_DGT_TA) == 0 then OPCIONES() -- Si pulsa A lo mandamos a la función OPCIONES
end
if bit.band(data, PER_DGT_TX) == 0 then CREDITOS()  -- Si pulsa X lo mandamos a la funcion CREDITOS, 
end

if bit.band(data, PER_DGT_ST) == 0 then JUGAR() -- Fijaos que estamos usando funciones combinandolas con condicionales, aquí lo mando a el juego en sí que sería la función JUGAR que definimos antes
end


end -- fin del while eterno en el que le he metido para que este todo el rato mostrando el menú principal y esperando que pulsemos alguna cosa



while true do slSynch() end -- lo de siempre[/code]

Y listo, ahora veis mejor tal vez para que podemos usar las funciones. Solo faltaría hacer un juegazo con unos gráficos y sonido tremendos y meterlo en la función JUGAR :twisted: 

Una cosa, he aprovechado para meter algunos comandos nuevos de librerías de SEGA que repaso fugazmente:

[b]slTVOff()[/b]
Aquí necesitaba algo así como un CLS de BASIC (clear screen) para limpiar la pantalla y he usado esto. Por lo que veo según SEGA: 

[quote]Drawing end declaration - This function turns off scroll drawing processing in the monitor[/quote]

Esto me ha funcionado, va acompañado inevitablemente de:

[b]slTVOn()[/b]

[quote]Drawing start declaration - This function starts drawing in the scroll screen monitor -[/quote]

Y eso es todo. Con eso he conseguido que cada vez que llamemos a una función limpie la pantalla para que no se vea nada de la anterior.


Pues nada, eso es todo por hoy. Necesito, o sigo necesitando más bien, manejar gráficos ya.. pero todavía no lo he conseguido. Pido a algún alma caricativa que me eche una mano, jaja :roll: 

Nos vemos en las próximas lecciones. Un saludo!


