admin 管理员组

文章数量: 887021

PICO

1.3 认识PICO-8代码

        在上一篇里面我花了较大的篇幅来介绍了PICO-8,在我们熟悉了各类操作之后,就可以上手来制作自己的第一个游戏了。在那之前,让我们来认识一下PICO-8的Game Loop:

PICO-8 uses three specially-named functions to create what's called a game loop. The _init() function happens one time, then _update() and _draw() happen in a loop until your game ends. Here's the basic structure of the PICO-8 game loop and what each functions does:

 

        上面是Dylan在文章中对Game Loop的介绍,其实说的直白一点,就是PICO-8代码运行的流程:PICO-8为制作者定义了三个函数: _init(), _update(), _draw(),在游戏启动后,_init()内的代码首先运行,并且只运行一次,然后就是_update()和_draw()的交替循环运行,一个循环内,_update()内的代码首先执行,然后是_draw()内的代码,这是一个循环,然后就是下一个循环,_update()执行,_draw()执行……这样的循环在一秒内会发生30次,从而使游戏画面能实现变化。

        除了这三个函数,我们还可以定义其他的函数,基本格式:

        function 函数名()

        end

        现在我们就可以试着制作出一个小“游戏”:

function _init()make_player()
endfunction _update()move_player()
endfunction _draw()cls() --clear screendraw_player()
endfunction make_player()px=64py=64psprite=1
endfunction move_player()if (btn(0)) px-=1 --leftif (btn(1)) px+=1 --rightif (btn(2)) py-=1 --upif (btn(3)) py+=1 --down
endfunction draw_player()spr(psprite,px,py)
end

       

        将这段代码复制到代码区,然后别忘了绘制你的小精灵:

 

        按下Ctrl+R运行,这个时候按下↑↓←→,我们的小精灵就可以实现自由移动了。

        现在我们回过头来分析一下代码:除了刚才提到的三个基本函数,这段代码里面害定义了三个函数,分别是make_player(), move_player(), draw_player():

function make_player()px=64py=64psprite=1
end

        首先是make_player(),这个函数实际上只给定了三个参数,后面的draw_player()才会用到这三个参数:

function draw_player()spr(psprite,px,py)
end

        这里的spr()就是绘制精灵的函数,它需要三个参数,分别是精灵编号、X轴坐标,Y轴坐标,在draw_player()里面,三个参数全部是make_player()里面定义好的,所以在这里面可以直接用。

        游戏运行之后地图是一个128*128的正方形,左上角为原点,沿直线往右X坐标递增,沿直线往下Y坐标递增,所以(64, 64)这个坐标正好是屏幕的正中心,这也是为什么刚才我们运行游戏之后,精灵出现在了屏幕的正中心,如果我们修改一下px和py的值,比如改成(0, 0),精灵就会生成在屏幕的左上角。

        值得一提的是,真正的地图尺寸并不是128*128, 我试着给了px和py很大的值9999999999,编辑器没有报错,游戏正常运行,我也给了速度一个很大的值,在经过漫长的跋涉之后,我的小精灵出现在了目前的屏幕中(因为速度太快实际上只是一闪而过),这也从侧面说明,实际的地图大小有可能是不设上限的。

        坐标值同样也可以是负值,小精灵也会出现在对应的位置。如何拖动摄像机,显示出更多的地图,这就是我们后面需要探究的问题了。

        至于精灵的编号,这个就是在绘制界面可以看见的东西:

        

        要让精灵动起来,我们还需要第三个函数:

function move_player()if (btn(0)) px-=1 --leftif (btn(1)) px+=1 --rightif (btn(2)) py-=1 --upif (btn(3)) py+=1 --down
end

         这里就是很简单的通过if()函数来实现X、Y坐标的增加从而让精灵“运动起来”,btn()是对按键输入的监视器,下面是按键与编号的对应关系:

        

        在我们的PC上,从0到5对应的就是“←”、“→”、“↑”、“↓”、“Z”、"X"。

        在前文提过,Game Loop每秒发生30次,这里的move_player()最后也是要放到Game Loop中的,所以当我们连续按着某一个按键时,一秒内可以读入30次,对应的按键事件也会发生30次。反映在这段代码中就是小精灵会以30pix/s的速度在地图上运动。

        另外一提,每秒钟30次的刷新也就是我们通常所说的30帧,如果我们设置一个稍微大一点的速度,精灵的运动看起来就不那么连续了。

        现在,我们再回过头来看这段代码在三个基本函数里干了些什么:

function _init()make_player()
endfunction _update()move_player()
endfunction _draw()cls() --clear screendraw_player()
end

         首先是_init(),里面是make_player(),这样在一开始编译器就知道了三个参数的值;然后在_update()里面是move_player(),这样在我们按下按钮之后坐标值就可以及时更新;在_draw()里面除了draw_player()还有一个cls()函数——这个函数用来清屏,同样也是必不可少的,我们可以试试去掉cls()之后运行游戏:

         

        这样的结果说明在没有cls()指令的情况下,上一个循环所绘制的图形在下个循环依旧存在。

        在了解了每一个代码块的作用后,我们就可以知道这个“游戏”的运作逻辑了:首先是_init()里面设定了三个初始值,然后进入Game Loop,_update()函数读取按键并且修改坐标值,_draw()函数清除上一个循环的画面,然后在新的坐标绘制精灵……循环一直进行,直到我们退出游戏。

        这里思考一个小问题:_update()函数和_draw()函数里面的代码是否可以调换?

        从名字里面来看好像是不行的,update在编程里面一般是更新的意思,在这里就是数值更新;draw就是绘制的意思,在这个代码里面他们做了各自想做的事,并且配合默契;另外我们开头就说过_update()和_draw()有先后关系,_update()先于_draw()执行,这样一来关于这个问题的答案好像已经确定是不行了,因为没有_update()更新数值_draw()不太可能在正确的地方绘制出新的精灵。

        然而真的是这样吗?如果我们实际操作一下就会发现,游戏和之前一模一样。

        这就说明了两个事情:首先,编辑器并没有给_update()和_draw()划定特定的功能,只是让他们先后循环运行,更新数值的工作可以让_draw()来做,同样,绘图的工作也可以交给_update(),注意我之前是说“他们想做的事”,而不是“他们应该做的事”。执行的先后问题在不断的循环过程中好像也没有太大的意义,在上个循环中更新的数值传递给下个循环,下个循环利用上个循环的数据作图,然后更新数值,在传入下下个循环……工作模式是基本上没有变化的。就好比你和你的朋友在围着柱子绕圈,他也可以是在你的前面,也可以是在你的后面。

        不过为了代码的可读性,我们还是应该老老实实的让它们做各自想做的事。

        这一篇我用了3k多字介绍了Dylan书中两页的内容,大概讲清楚了PICO-8代码运作的一些基础的东西,并且制作了一个并不是游戏的游戏。

        下一篇我们还会跟随Dylan的脚步,来制作第一个真正的游戏。

本文标签: PICO