Академический Документы
Профессиональный Документы
Культура Документы
Lua
Antes de nada, el lenguaje Lua, es un lenguaje de programacion muy versatil y potente, se a implementado un lanzador de lua, (LuaPlayer) que puede ejecutar cualquier archivo de codigo fuente escrito en Lua, uno de los aspectos mas interesantes del lua es que no hay que compilar nada, lo que hace mas facil el dessaroyo de aplicaciones, y por esta misma razon, cada programa de en lua, es su propio codigo fuente. Asi que cuando no sabemos como implementar algo, siempre podemos hechar un ojo a cualquier programa que haga una funcion parecida. El lua player es un lanzador de aplicaciones, por defecto nos lanza el Lowser, que es un Browser para lua, desde el que podremos explorar la memory y lanzar cualquier aplicacion en lua. Si introducimos el codigo de nuestro programa con el nombre script.lua en el directorio raiz del LuaPlayer, en vez del lowser ejecutara nuestro codigo, si en vez de eso, en la carpeta de aplicaciones, creamos una subcarpeta con el nombre deseado para el programa y lo introducimos en esta con el nombre de index.lua podremos lanzarlo desde el Lowser Para probar nuestro programa y evitar el tener que conectar el usb, copiar desde el ordenador, desactivar usb, arrancar el lua.... existen dos alternativas, la primera y mas comoda, es usar la version para windows del lanzador de Lua, LuaPlayer for Windows y probar nuestro codigo desde el, la manera correcta es crear un archivo de texto, con la extension .cmd que contenga la siguiente linea: luaplayer nombre_del_programa.lua, y tener tanto el .cmd, como el .lua en la carpeta del luaPlayer for windows. Muy util para experimentos en Lua puro es LuaIDE, donde puedes introducir los programas y ejecutarlos paso a paso, observando los cambios en las variables. Otra manera es descargar la version independiente de Lua (lua.exe para windows) abrir el interprete de comandos e iniciar lua.exe, donde podremos introducir expresiones en Lua como por ejemplo for i=1,10 do io.write(i .. \n) end.
La resolucion de la PSP es de 480 pixels de ancho y 272 pixels de alto. Color.new crea un nuevo objeto de color. Los argumentos son rojo, verde, azul y alpha (opcional),Que tienen un rango desde 0 hasta 255 para intensidad maxima. Esto es conocido como el modelo de color RGB. screen:print dibuja un texto en la pantalla, donde los 2 primeros argumentos son las coordenadas x e y en la pantalla, despues el texto como cadena de caracteres y un color opcional (negro por defecto). La coordenada X comienza en la derecha y la Y en la parte superior.
Yorddy
Existen dos buffers de pantalla: Uno visible y otro invisible. Todas las funciones de dibujo/escritura van al bufer no visible. Esto significa que lo que escribes no es visible hasta que llamas a screen.flip(), Que intercambia los dos buffers de pantalla. Esto es conocido como el double-buffering. Finalmente el bucle while llama a waitVblankStart en un bucle infinito. Si no escribes algo asi al final, tu script finalizara y no veras el resultado impreso en pantalla, esto es debido a que arranco desde Lowser, el GUI Lowser se mostrara y si se inicio como un script independiente la pregunta de reiniciar sera mostrada. Si no escribes la funcion de espera, pero usas un bucle infinito vacio, este generaria mucho uso de CPU, esto es debido a que la funcion da la opcion al kernel de dormir.
Animaciones
Comprender como se representan los pixeles en pantalla es importante para escribir juegos. La pantalla de la PSP, como muchas otras pantallas, tiene el mismo concepto que los antiguos tubos de imagen: Un haz de electrones comienza a barrer desde la esquina superior izquierda de la pantalla y va abanzando escaneando todas las lineas de arriba a abajo. (el amigo abismo que es electronico podra explicarlo mejor), cuando llega abajo necesita algun tiempo para volver al comienzo, esto es llamado vertical blank (vBlank), Por supuesto, en la PSP no existe realmente este haz de electrones, pero podemos pensar que funciona de esta manera, con el script "screen.waitVblankStart" hace que el programa espere hasta que comience el proximo barrido, durante esta espera, ningun pixel es escrito en la pantalla, lo que te da la oportunidad de intercambiar la screen y el offscreen para evitar parpadeos o destellos. Vamos a ver como mostrar una animacion haciendo uso del intercambio sincronizado de pantallas: --Activa el usb (esto no es realmente necesario) System.usbDiskModeActivate() --creamos un nuevo objeto de color verde green = Color.new(0, 255, 0) --variable time inicializada a cero time = 0 --pi almacena 3,14... arcotangente de 1 (radian) * 4 pi = math.atan(1) * 4 --bucle infinito while true do --limpia la pantalla al comienzo de cada barrido screen:clear() --vamos calculando el seno para cada momento time x = math.sin(pi * 2 / 360 * time) * 150 + 192.5 --mostramos hola mundo en la posicion seno(time) screen:print(x, 100, "Hello World!", green) --incrementamos tiempo time = time + 1 --volvemos a cero cuando el time supera 360 if time >= 360 then time = 0 end --esperamos al proximo escaneo screen.waitVblankStart() --intercambiamos las pantallas screen.flip() --si se pulsa start se sale del script pad = Controls.read() if pad:start() then break end end En el bucle while, primero se limpia el offscreen. Despues el texto se dibuja en la pantalla, se espera al siguente escaneo de pantalla, se intercambia el screen y el offscreen. En la PSP la velocidad de refresco es 60Hz, lo que significa que eltexto necesita 6 segundos para volver a empezar desde la misma posicion. (la funcion seno tiene un periodo de 2*pi, asi que para un periodo completo "time" necesita ir desde 0 a 360 y "time" se incrementa 60 veces por segundo, lo que significa que un periodo son 6 segundos). Finalmente se comprueba si se a pulsado start, que sale del bucle. Puedes usar este codigo como comienzo para tus propios programas. La funcion "System.usbDiskModeActivate" al comienzo activa el USB, y la comprobacion de la tecla start sale del bucle. Si cargas este programa como script.lua desde el directorio raiz del Lua player, la tecla start reiniciara el
Yorddy
programa, asi podras acceder al archivo,modificarlo con un editor de textos y reiniciarlo para ver los cambios. mientras que si lo ejecutas desde lowser te debolvera a este mismo. Ahora lo haremos con imagenes, primero copia esta imagen como "background.png" en tu PSP:
Yorddy
transparentes) dibuja las partes estaticas de tu juego en esta imagen y en cada bucle despues del vblank, primero dibuje el fondo en pantalla, despues la imagen con las partes estaticas y finalmente las partes dinamicas. Mira el juego de la serpiente como ejemplo de esto.
Controles
Puedes usar los controles de la PSP con la clase Controls. "Control.read()" lee el estado actual de un boton determinado, como por ejemplo la cruz. El resultado sera true si el boton cruz es pulsado, y falso en cualquier otro caso. analogX y analogY retorna la posicion del pad analogico. El rango va desde -128 a 127, pero los valores por debajo de 32 pueden ser producidos aunque el pad este centrado. En el ejemplo de un programa de dibujo, usamos el analogico para mover el cursor, mantener pulsada la cruz dibujara una linea, select guardara la imagen y start terminara.
red = Color.new(255, 0, 0); black = Color.new(0, 0, 0); white = Color.new(255, 255, 255); canvas = Image.createEmpty(480, 272) canvas:clear(white) brush = {} eraser = {} x0 = 0 y0 = 0 x1 = 0 y1 = 0 while true do pad = Controls.read() dx = pad:analogX() if math.abs(dx) > 32 then x0 = x0 + dx / 64 end dy = pad:analogY() if math.abs(dy) > 32 then y0 = y0 + dy / 64 end if pad:cross() then canvas:drawLine(x0, y0, x1, y1, black) end x1 = x0 y1 = y0 screen:blit(0, 0, canvas, 0, 0, canvas:width(), canvas:height(), false) screen:drawLine(x1 - 5, y1, x1 + 5, y1, red) screen:drawLine(x1, y1 - 5, x1, y1 + 5, red) screen.waitVblankStart() screen.flip() if pad:start() then break end if pad:select() then screen:save("screenshot.tga") end end
En lugar del comando drawLine con el color rojo para la cruz, puedes usar screen:blit(x1, y1, yourCursorImage) para dibujar una imagen con tu cursor y puedes eliminar el drawLine cuando se pulsa la cruz, si no quieres implementar un programa de dibujo. Puedes detener la repeticion en los controles aadiendo la siguiente linea de codigo.
Manual Bsico de Lua
Yorddy
function controls() pad = Controls.read() if pad ~= oldPad then --yourcodehere end oldPad = pad end
Sonido
Lua Player soporta sonidos en formato WAV y musica en los formatos MOD: UNI, IT, XM, S3M, MOD, MTM, STM, DSM, MED, FAR, ULT y 669. Reproducir musica es simple: Por ejemplo, para reproducir el archivo stranglehold.xm (composed by Jeroen Tel, (C) 1995 Maniacs of Noise) para el juego de la serouente (Jeroen permite que la usemos en este juego), que esta incluido en la distrubucion estandart de Lua Player, solamente llama a "Music.playFile("stranglehold.xm", true)". Si lo especificas "false" en vez de "true", el sonido no se repetira. Llama "Music.stop()" para detener la musica.
Yorddy
Donde "high" es una variable global, que contiene el record actual. Mira Manual Lua para ms detalles de que parmetros puedes usar para las funciones de lectura/Escritura. Para un ejemplo mas complicado se podr
Las baldosas:
Yorddy
end drawTile(tile, x - 1, y - 1) end screen.waitVblankStart() screen:flip()
end
Este es el resultado:
El modo USB hace mas facil editar el mapa, porque te permite abrir tu editor salvar y recargarlo pulsando "start" Ahora necesitamos alguna animacion:
El programa que muestra el jugador y le permite moverse, comiendo puntos y aadiendo puntuacion: -- cargar imagenes tiles = Image.load("tiles.png") figure = Image.load("figure.png") -- el mapa mapSource = { "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", "mmeaaaaaaaaaaaaaaaaaaaaaaaafmm", "mmdpnnnnnnnnnnnnnnnnnnnnnnpbmm", "mmdokcccccclnkccccccccccclnbmm", "mmdojaaaaafdnbmmmmmmmmmmmdnbmm", "mmdooooooobdnbmmmmmmmmmmmdnbmm", "mmdokccclobdnbmmmmmmmmmmmdnbmm", "mmdobmmmdobdnbmmmmmmmmmmmdnbmm", "mmdobmmmdobdnjaaaaaaaaaafdnbmm", "mmdobmmmdpbdnnnnnnnnnnnnbdnbmm", "mmdobmmmhcghcccccccccclnbdnbmm", "mmdojaaaaaaaaaaaaaaaaainjinbmm", "mmdpnnnnnnnnnnnnnnnnnnnnnnpbmm", "mmhccccccccccccccccccccccccgmm", "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm" } -- imagen en el offsreen, donde dibujamos el mapa board = Image.createEmpty(480, 272) -- dibuja una baldosa en el mapa: function drawTile(tile, x, y) tile = string.byte(tile, 1) - string.byte("a") local tileX = math.mod(tile, 4) local tileY = math.floor(tile / 4) board:blit(16 * x, 16 * y, tiles, 17 * tileX + 1, 17 * tileY + 1, 16, 16, false) end
Yorddy
-- copia el mapa fuente a un vector para facilitar el acceso y dibujarlo en el offscreen map = {} for y = 1, 17 do line = mapSource[y] map[y] = {} for x = 1, 30 do tile = string.sub(line, x, x) map[y][x] = tile drawTile(tile, x - 1, y - 1) end end -- posicion actual del jugador playerX = 6 playerY = 14 -- imagen actual de animacion del jugador animation = 0 -- 1 = incremento en la animacion, -1: decremento animationDirection = 1 -- contador de freno de la animacion animationSlowDown = 0 -- control de la velocidad de movimiento. a speedStep == 0, el -- ultimo movimiento sera evaluado, los otros movimientos solamente seran -- salvados speedStep = 0 -- ultima direccion del pad dx = 0 dy = 0 -- puntuacion actual score = 0 -- color del texto white = Color.new(255, 255, 255) while true do -- lectura del pad pad = Controls.read() if pad:start() then -- salirse al lowser / reiniciar aplicacion dependiendo de como se cargara este break end if speedStep == 0 then -- salva la posicion anterior del jugador oldPlayerX = playerX oldPlayerY = playerY -- aadir ultimo movimiento playerX = playerX + dx playerY = playerY + dy -- comprobar el nuevo valdosin newTile = map[playerY][playerX]
Yorddy
-- si la posicion no esta permitida, reestablece la posicion anterior if newTile ~= "n" and newTile ~= "p" and newTile ~= "o" then playerX = oldPlayerX playerY = oldPlayerY end -if if if S esta en una baldosa que puede ser comida,la come: newTile == "p" then score = score + 5 end newTile == "o" then score = score + 1 end newTile == "p" or newTile == "o" then -- pone el fondo map[playerY][playerX] = "n" -- dibuja el fondo drawTile("n", playerX - 1, playerY - 1)
end
-- reestablece la ultima posicion dx = 0 dy = 0 else -- comprobar el pad if pad:up() then dy = -1 elseif pad:down() then dy = 1 elseif pad:left() then dx = -1 elseif pad:right() then dx = 1 end
end
-- incrementar el contador de velocidad de pasos speedStep = speedStep + 1 if speedStep == 5 then speedStep = -1 end -- dibuja en el offscreen screen:blit(0, 0, board, 0, 0, board:width(), board:height(), false) -- dibuja la animacion actual del jugador screen:blit((playerX - 1) * 16 - 4, (playerY - 1) * 16 - 4, figure, 1 + 25 * animation, 1, 24, 24) -- calcula la proxima imagen de animacion animationSlowDown = animationSlowDown + 1 if animationSlowDown == 3 then animationSlowDown = 0 animation = animation + animationDirection if animation == 4 then animationDirection = -1 elseif animation == 0 then animationDirection = 1 end end -- imprime puntuacion screen:print(10, 260, "Score: " .. score, white) -- espera el proximo refresco de pantalla para dibujar el offscreen screen.waitVblankStart()
Yorddy
end screen:flip()
Notar que las baldosas son dibujadas en el offscreen, debido a que dibujar multiples baldosas es mas lento que dibujar una imagen del mismo tamao que todas las baldosas. Con este truco podemos alcanzar los 60fps. Algunas modificaciones posibles son algunos oponentes, usar un fondo transparente para los azulejos y dibujar estos sobre un fondo predefinido, o usar multiples mascaras con multiples fondos o mapas que coordi