Lua Player 指南
前提条件你应该对lua编程语言的基础有所了解,这个网址下面就有一些比较不错的Lua的教程http://lua-users.org/wiki/TutorialDirectory.而LuaIDE在纯的Lua环境下对你实验很有帮助,在那里你可以键入一些程序并且一步一步的运行,来观察其中的变量是如何改变的.还有一种方式就是下载windows版本的Lua(lua.exe),以命令行的方式来启动lua.exe,然后在里面输入Lua表达式,比如像”for i=1,10 do io.write(i..”\n”) end”.
Hello World首先按照readme文件中描述的步骤安装Lua Player.完成之后让我们从一个简单的脚本开始吧:
-- create a new Color object
green = Color.new(0, 255, 0)
-- show some text on offscreen
screen:print(200, 100, "Hello World!", green)
-- flip visible and offscreen
screen.flip()
-- wait forevever
while true do
screen.waitVblankStart()
end
把上面这些内容输入到文本文档中,并以”script.lua”作为他的文件名,把它放到你的记忆棒用来存放EBOOT.PBP的同一个目录中.当你启动Lua player之后,你的可爱的psp屏幕上应该可以看到这个枯燥的图片:
psp 的屏幕的分辨率是480*272(单位像素)的.”Color.new”这条语句建立了一个新的颜色对象.参数分别是red,green,blue和alpha(可选),每一个参数的变化范围都是从0到255.这其实就是RGB颜色模型. "screen:print"这条语句在屏幕上显示出了一些文本,其中前两个参数是要显示的文本在屏幕中的位置x,y坐标值,这两个参数后面紧接着要显示的文本和一个可选的颜色参数(默认是黑色).坐标值x是从屏幕的左边开始的,坐标值y是从屏幕顶端往下增长的.
这里我们使用了两个屏幕缓冲:一个离屏缓冲和一个可视缓冲。所有的绘图函数都是作用在离屏缓冲上的。这就意味着直到调用了screen.flip(),离屏缓冲和可视缓冲才能互相交换,从而显示出你要显示出的文字来。这其实就是所谓的双缓冲技术。这种技术是通过一种叫做page-flipping(翻页技术)来实现的,这就是问什么它的名字叫做“flip“啦。
在最后的那个while循环中 无限的调用了waitVblankStart这个函数。如果你不以类似这样的方式结尾的话,当你的脚本结束时,你将不会看到你所想要看到的结果,因为你如果从Lowser中启动它的话你看到的将是Lowser的图形界面,如果把它作为一个单独的脚本来运行的话你看到将是屏幕上显示是否还要重新运行一遍的提示。如果你只是用一个空循环而没有用那些等待函数的话,这将会占用大量的cpu资源。
动画理解存储在内存中的像素是如何显示在屏幕上的对于编写游戏是非常重要的。许多显示设备包括psp的显示原理,其实都和老式的阴极射线管的原理相类似。一条光线从屏幕的左上端开始一条线一条线往下扫描。在最底部时这条光要返回左上端时要花费一些时间而这段时间就叫做垂直空白(vblank),这是因为在扫描线在返回起始扫描位置时它是处在非激活状态的。当然了,在psp中其实并没有这条扫描线。但是你可以就认为它是这么工作的。当执行”screen.waitVblankStart()”后,脚本将会等待到这次vblank的开始.在vblank期间将不会显示任何像素点,这就给了我们时间来进行离屏和显示屏之间的切换,从而避免了屏幕闪烁。
下面让我们看看通过同步的页面切换来实现的动画是个什么样的吧:
System.usbDiskModeActivate()
green = Color.new(0, 255, 0)
time = 0
pi = math.atan(1) * 4
while true do
screen:clear()
x = math.sin(pi * 2 / 360 * time) * 150 + 192.5
screen:print(x, 100, "Hello World!", green)
time = time + 1
if time >= 360 then
time = 0
end
screen.waitVblankStart()
screen.flip()
pad = Controls.read()
if pad:start() then
break
end
end
在while循环当中,首先对离屏进行清屏,然后在离屏上面写上一些文字,然后脚本等待vblank的开始,之后在交换可见屏和离屏。Psp的垂直刷新率是60Hz,这就意味着文字需要六秒钟的时间才会回到原来的地方(sin函数的周期是2*pi,所以一个完整的周期就是从0度到360度,而每秒钟增加六十次,所以一个周期就要花费6秒)。在代码的最后通过检查是否按下了start这个按键,来退出循环。
你可以使用这条语句作为你自己的程序的开始。System.usbDiskModeActivate()这条语句启动了usb模式,在循环的最后是按键代码:当你按下start按键后,LuaPlayer程序就重新运行你的程序一遍。这个就让我们在开发时有了一个快速的周转时间:首先在psp上运行你的脚本程序,当你开启了usb功能时,你就可以通过usb驱动来在一个文本编辑器打开你的脚本,保存你对脚本改动,然后只要每按下start按键就可以马上运行经过改动后的脚本了。
图像
首先拷贝下面这个图片到你的psp上,并以background.png作为它的文件名:
然后还有这个图片,把它命名为smiley.png
下面就这个笑脸的动画程序了:
System.usbDiskModeActivate()
green = Color.new(0, 255, 0)
time = 0
pi = math.atan(1) * 4
background = Image.load("background.png")
smiley = Image.load("smiley.png")
while true do
screen:blit(0, 0, background, 0, 0, background:width(), background:height(), false)
x = math.sin(pi * 2 / 250 * time) * 200 + 220.5
y = 172 - math.abs(math.sin(pi * 2 / 125 * time) * 150)
screen:blit(x, y, smiley)
time = time + 1
if time >= 500 then
time = 0
end
screen.waitVblankStart()
screen.flip()
pad = Controls.read()
if pad:start() then
break
end
end
你可以看到我们上面这个程序的主循环体的大体结构和前面例子的结构是很像的。不过这次没有使用screen:clear()这个函数拉,而是调用了screen:blit,通过它来描绘了背景。然后screen:blit(x, y, smiley)这一句则在背景之上描绘了另一个图像。这里用到的参数比较少,因为我们对blit函数使用了默认的参数,我们把alpha这个参数设为真。这意味着所有在这幅图片中透明的像素点是不会被参与blit过程。
比如说某些图像程序会这样显示你的图片:
我们可以看到当Lua Player中alpha这个参数被设为真时,各自花纹图案是透明的并没有被描绘出来。
如果你有很多物体要画在屏幕上的话,使用多层技术可能会更快一些:通过Image.createEmpty建立一个空的图像(空的图像默认是由透明的像素点构成的),把你游戏中的静态部分描绘到这个图像上,然后对于vblank后的每次循环,首先在屏幕上画出背景,然后是包含静态部分的那个图片,最后再画那些动态部分。具体你可参阅snake这个游戏是怎么做到的。
控制你可以通过control类来使用你psp上的控制部件。Controls.read()能够读取到psp控制部件的当前状态,举个例子来说当x键按下时,那么cross这个函数就会返回真值(true)否着就会返回假值(false)。analogX 和 analogY可以返回模拟模拟摇杆的位置,它的范围是-128到127,但是即使当摇杆在中间位置时也会产生些小于32的数值。下面是一个画图程序。通过模拟摇杆来移动光标,按下cross来绘画,select是截图按钮,start键则是结束。
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
例图(我知道我不是一个艺术家)
声音待续
Lowser集成环境待续
文件输入输出待续
完整的带有卷轴系统的游戏例子待续
19. August 2005, Frank Buß 中文翻译:coalight